Merge changes from topic "ui-material-migration" into androidx-master-dev
* changes:
Optimizes imports for compose:material:* after the package migration
Moves ui-material to compose/material/material
diff --git a/buildSrc/build_dependencies.gradle b/buildSrc/build_dependencies.gradle
index f319223..657db32 100644
--- a/buildSrc/build_dependencies.gradle
+++ b/buildSrc/build_dependencies.gradle
@@ -20,7 +20,7 @@
// NOTE: lint versions *must* be kept in sync with agp
if (isUiProject) {
- build_versions.kotlin = "1.4.0-rc"
+ build_versions.kotlin = "1.4.0"
build_versions.kotlin_coroutines = "1.3.6"
build_versions.agp = '4.2.0-alpha06'
build_versions.lint = '27.2.0-alpha06'
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 59c34d4..a8664e3 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -80,7 +80,7 @@
val MEDIA2 = Version("1.1.0-alpha02")
val MEDIAROUTER = Version("1.2.0-alpha02")
val NAVIGATION = Version("2.4.0-alpha01")
- val PAGING = Version("3.0.0-alpha05")
+ val PAGING = Version("3.0.0-alpha06")
val PALETTE = Version("1.1.0-alpha01")
val PRINT = Version("1.1.0-alpha01")
val PERCENTLAYOUT = Version("1.1.0-alpha01")
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index f26a85b..4a2d1a6 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -93,6 +93,15 @@
const val SKIKO_LINUX = "org.jetbrains.skiko:skiko-jvm-runtime-linux:$SKIKO_VERSION"
const val SKIKO_MACOS = "org.jetbrains.skiko:skiko-jvm-runtime-macos:$SKIKO_VERSION"
const val SKIKO_WINDOWS = "org.jetbrains.skiko:skiko-jvm-runtime-windows:$SKIKO_VERSION"
+val SKIKO_CURRENT_OS by lazy {
+ val os = System.getProperty("os.name")
+ when {
+ os == "Mac OS X" -> SKIKO_MACOS
+ os.startsWith("Win") -> SKIKO_WINDOWS
+ os.startsWith("Linux") -> SKIKO_LINUX
+ else -> throw Error("Unsupported OS $os")
+ }
+}
const val TRUTH = "com.google.truth:truth:1.0.1"
const val XERIAL = "org.xerial:sqlite-jdbc:3.25.2"
const val XPP3 = "xpp3:xpp3:1.1.4c"
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
index 4917fa9..d0441f7 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
@@ -30,6 +30,7 @@
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Build;
import android.util.Size;
import android.view.WindowManager;
@@ -90,9 +91,7 @@
@SmallTest
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP,
- maxSdk = Build.VERSION_CODES.P //TODO (b/149669465) : Some robolectric tests will fail on Q
-)
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
public final class Camera2DeviceSurfaceManagerTest {
private static final String LEGACY_CAMERA_ID = "0";
private static final String LIMITED_CAMERA_ID = "1";
@@ -548,10 +547,21 @@
((ShadowCameraManager) Shadow.extract(cameraManager))
.addCamera(cameraId, characteristics);
- shadowCharacteristics.set(
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
- StreamConfigurationMapUtil.generateFakeStreamConfigurationMap(
- mSupportedFormats, mSupportedSizes));
+ // Current robolectric can support to directly mock a StreamConfigurationMap object if
+ // the testing platform target is equal to or newer than API level 23. For API level 21
+ // or 22 testing platform target, keep the original method to create a
+ // StreamConfigurationMap object via reflection.
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ shadowCharacteristics.set(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
+ StreamConfigurationMapUtil.generateFakeStreamConfigurationMap(mSupportedFormats,
+ mSupportedSizes));
+ } else {
+ StreamConfigurationMap mockMap = mock(StreamConfigurationMap.class);
+ when(mockMap.getOutputSizes(anyInt())).thenReturn(mSupportedSizes);
+ shadowCharacteristics.set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
+ mockMap);
+ }
@CameraSelector.LensFacing int lensFacingEnum = CameraUtil.getLensFacingEnumFromInt(
lensFacing);
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
index b12db61..e444a45b 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
@@ -26,6 +26,7 @@
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Build;
import android.util.Size;
@@ -72,9 +73,7 @@
@SmallTest
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP,
- maxSdk = Build.VERSION_CODES.P //TODO (b/149669465) : Some robolectric tests will fail on Q
-)
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
public class SupportedSizeConstraintsTest {
private static final String BACK_CAMERA_ID = "0";
private static final int DEFAULT_SENSOR_ORIENTATION = 90;
@@ -223,10 +222,21 @@
int[] supportedFormats = mSupportedFormats;
- shadowCharacteristics.set(
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
- StreamConfigurationMapUtil.generateFakeStreamConfigurationMap(supportedFormats,
- supportedSizes));
+ // Current robolectric can support to directly mock a StreamConfigurationMap object if
+ // the testing platform target is equal to or newer than API level 23. For API level 21
+ // or 22 testing platform target, keep the original method to create a
+ // StreamConfigurationMap object via reflection.
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ shadowCharacteristics.set(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
+ StreamConfigurationMapUtil.generateFakeStreamConfigurationMap(supportedFormats,
+ supportedSizes));
+ } else {
+ StreamConfigurationMap mockMap = mock(StreamConfigurationMap.class);
+ when(mockMap.getOutputSizes(anyInt())).thenReturn(supportedSizes);
+ shadowCharacteristics.set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
+ mockMap);
+ }
@CameraSelector.LensFacing int lensFacingEnum = CameraUtil.getLensFacingEnumFromInt(
CameraCharacteristics.LENS_FACING_BACK);
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
index 2064fb8..08fb3e5 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
@@ -29,6 +29,7 @@
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Build;
import android.util.Pair;
import android.util.Rational;
@@ -93,9 +94,7 @@
@SmallTest
@RunWith(RobolectricTestRunner.class)
@DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP,
- maxSdk = Build.VERSION_CODES.P //TODO (b/149669465) : Some robolectric tests will fail on Q
-)
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
public final class SupportedSurfaceCombinationTest {
private static final String CAMERA_ID = "0";
private static final int DEFAULT_SENSOR_ORIENTATION = 90;
@@ -1899,10 +1898,21 @@
int[] supportedFormats = isRawSupported(capabilities)
? mSupportedFormatsWithRaw : mSupportedFormats;
- shadowCharacteristics.set(
- CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
- StreamConfigurationMapUtil.generateFakeStreamConfigurationMap(supportedFormats,
- supportedSizes));
+ // Current robolectric can support to directly mock a StreamConfigurationMap object if
+ // the testing platform target is equal to or newer than API level 23. For API level 21
+ // or 22 testing platform target, keep the original method to create a
+ // StreamConfigurationMap object via reflection.
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ shadowCharacteristics.set(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
+ StreamConfigurationMapUtil.generateFakeStreamConfigurationMap(supportedFormats,
+ supportedSizes));
+ } else {
+ StreamConfigurationMap mockMap = mock(StreamConfigurationMap.class);
+ when(mockMap.getOutputSizes(anyInt())).thenReturn(supportedSizes);
+ shadowCharacteristics.set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP,
+ mockMap);
+ }
@CameraSelector.LensFacing int lensFacingEnum = CameraUtil.getLensFacingEnumFromInt(
CameraCharacteristics.LENS_FACING_BACK);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
index 187e794..5fb4ba1 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
@@ -19,10 +19,15 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.util.Rational;
+import android.view.Surface;
+
import androidx.camera.core.UseCase;
+import androidx.camera.core.ViewPort;
import androidx.camera.core.impl.CameraInternal;
import androidx.camera.testing.fakes.FakeCamera;
import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
@@ -174,4 +179,35 @@
verify(callback).onUnbind();
}
+
+ @Test
+ public void addExistingUseCase_viewPortUpdated()
+ throws CameraUseCaseAdapter.CameraException {
+ Rational aspectRatio1 = new Rational(1, 1);
+ Rational aspectRatio2 = new Rational(2, 1);
+
+ // Arrange: set up adapter with aspect ratio 1.
+ CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
+ mFakeCameraSet,
+ mFakeCameraDeviceSurfaceManager);
+ cameraUseCaseAdapter.setViewPort(
+ new ViewPort.Builder(aspectRatio1, Surface.ROTATION_0).build());
+ FakeUseCase fakeUseCase = spy(new FakeUseCase());
+ cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
+ // Use case gets aspect ratio 1
+ assertThat(fakeUseCase.getViewPortCropRect()).isNotNull();
+ assertThat(new Rational(fakeUseCase.getViewPortCropRect().width(),
+ fakeUseCase.getViewPortCropRect().height())).isEqualTo(aspectRatio1);
+
+ // Act: set aspect ratio 2 and attach the same use case.
+ reset(fakeUseCase);
+ cameraUseCaseAdapter.setViewPort(
+ new ViewPort.Builder(aspectRatio2, Surface.ROTATION_0).build());
+ cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
+
+ // Assert: the viewport has aspect ratio 2.
+ assertThat(fakeUseCase.getViewPortCropRect()).isNotNull();
+ assertThat(new Rational(fakeUseCase.getViewPortCropRect().width(),
+ fakeUseCase.getViewPortCropRect().height())).isEqualTo(aspectRatio2);
+ }
}
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 a2ca7d4..87be783 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,8 +564,7 @@
*/
@RestrictTo(Scope.LIBRARY)
@Nullable
- @SuppressWarnings("KotlinPropertyAccess")
- protected Rect getViewPortCropRect() {
+ public Rect getViewPortCropRect() {
return mViewPortCropRect;
}
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 6814c12..365a3a4 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
@@ -157,7 +157,7 @@
for (UseCase useCase : useCases) {
if (mUseCases.contains(useCase)) {
- Log.e(TAG, "Attempting to attach already attached UseCase");
+ Log.d(TAG, "Attempting to attach already attached UseCase");
} else {
useCaseListAfterUpdate.add(useCase);
newUseCases.add(useCase);
@@ -189,7 +189,8 @@
mViewPort.getLayoutDirection(),
suggestedResolutionsMap);
for (UseCase useCase : useCases) {
- useCase.setViewPortCropRect(cropRectMap.get(useCase));
+ useCase.setViewPortCropRect(
+ Preconditions.checkNotNull(cropRectMap.get(useCase)));
}
}
@@ -279,38 +280,42 @@
@NonNull List<UseCase> currentUseCases) {
List<SurfaceConfig> existingSurfaces = new ArrayList<>();
String cameraId = mCameraInternal.getCameraInfoInternal().getCameraId();
+ Map<UseCase, Size> suggestedResolutions = new HashMap<>();
- Map<UseCaseConfig<?>, UseCase> configToUseCaseMap = new HashMap<>();
-
+ // Get resolution for current use cases.
for (UseCase useCase : currentUseCases) {
SurfaceConfig surfaceConfig =
mCameraDeviceSurfaceManager.transformSurfaceConfig(cameraId,
useCase.getImageFormat(),
useCase.getAttachedSurfaceResolution());
existingSurfaces.add(surfaceConfig);
+ suggestedResolutions.put(useCase, useCase.getAttachedSurfaceResolution());
}
- for (UseCase useCase : newUseCases) {
- UseCaseConfig.Builder<?, ?, ?> defaultBuilder = useCase.getDefaultBuilder(
- mCameraInternal.getCameraInfoInternal());
+ // Calculate resolution for new use cases.
+ if (!newUseCases.isEmpty()) {
+ Map<UseCaseConfig<?>, UseCase> configToUseCaseMap = new HashMap<>();
+ for (UseCase useCase : newUseCases) {
+ UseCaseConfig.Builder<?, ?, ?> defaultBuilder = useCase.getDefaultBuilder(
+ mCameraInternal.getCameraInfoInternal());
- // Combine with default configuration.
- UseCaseConfig<?> combinedUseCaseConfig =
- useCase.applyDefaults(useCase.getUseCaseConfig(),
- defaultBuilder);
- configToUseCaseMap.put(combinedUseCaseConfig, useCase);
+ // Combine with default configuration.
+ UseCaseConfig<?> combinedUseCaseConfig =
+ useCase.applyDefaults(useCase.getUseCaseConfig(),
+ defaultBuilder);
+ configToUseCaseMap.put(combinedUseCaseConfig, useCase);
+ }
+
+ // Get suggested resolutions and update the use case session configuration
+ Map<UseCaseConfig<?>, Size> useCaseConfigSizeMap = mCameraDeviceSurfaceManager
+ .getSuggestedResolutions(cameraId, existingSurfaces,
+ new ArrayList<>(configToUseCaseMap.keySet()));
+
+ for (Map.Entry<UseCaseConfig<?>, UseCase> entry : configToUseCaseMap.entrySet()) {
+ suggestedResolutions.put(entry.getValue(),
+ useCaseConfigSizeMap.get(entry.getKey()));
+ }
}
-
- // Get suggested resolutions and update the use case session configuration
- Map<UseCaseConfig<?>, Size> useCaseConfigSizeMap = mCameraDeviceSurfaceManager
- .getSuggestedResolutions(cameraId, existingSurfaces,
- new ArrayList<>(configToUseCaseMap.keySet()));
-
- Map<UseCase, Size> suggestedResolutions = new HashMap<>();
- for (Map.Entry<UseCaseConfig<?>, UseCase> entry : configToUseCaseMap.entrySet()) {
- suggestedResolutions.put(entry.getValue(), useCaseConfigSizeMap.get(entry.getKey()));
- }
-
return suggestedResolutions;
}
@@ -333,6 +338,7 @@
*/
public static final class CameraId {
private final List<String> mIds;
+
CameraId(LinkedHashSet<CameraInternal> cameraInternals) {
mIds = new ArrayList<>();
for (CameraInternal cameraInternal : cameraInternals) {
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewTest.java b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewTest.java
index 36c09c5..3b36b223 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewTest.java
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewViewTest.java
@@ -31,6 +31,7 @@
import static org.mockito.Mockito.when;
import android.Manifest;
+import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.SurfaceTexture;
@@ -63,6 +64,7 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.rule.GrantPermissionRule;
@@ -90,6 +92,8 @@
@Rule
public final GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
Manifest.permission.CAMERA);
+
+ private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
@Rule
public final ActivityTestRule<FakeActivity> mActivityRule = new ActivityTestRule<>(
FakeActivity.class);
@@ -277,27 +281,171 @@
}
@Test
- @UiThreadTest
- public void canCreateMeteringPointFactory() {
+ public void canCreateValidMeteringPoint() throws Exception {
final CameraInfo cameraInfo = createCameraInfo(90,
CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, CameraSelector.LENS_FACING_BACK);
final PreviewView previewView = new PreviewView(mContext);
- setContentView(previewView);
- Preview.SurfaceProvider surfaceProvider = previewView.createSurfaceProvider();
- mSurfaceRequest = createSurfaceRequest(cameraInfo);
- surfaceProvider.onSurfaceRequested(mSurfaceRequest);
+ mInstrumentation.runOnMainSync(() -> {
+ setContentView(previewView);
+ mSurfaceRequest = createSurfaceRequest(cameraInfo);
+ Preview.SurfaceProvider surfaceProvider = previewView.createSurfaceProvider();
+ surfaceProvider.onSurfaceRequested(mSurfaceRequest);
+ });
+
+ waitForLayoutReady(previewView);
+
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
+ MeteringPoint point = factory.createPoint(100, 100);
+ assertPointIsValid(point);
+ }
+
+ private void assertPointIsValid(MeteringPoint point) {
+ assertThat(point.getX() >= 0f && point.getX() <= 1.0f).isTrue();
+ assertThat(point.getY() >= 0f && point.getY() <= 1.0f).isTrue();
+ }
+
+ @Test
+ public void meteringPointFactoryAutoAdjusted_whenViewSizeChange() throws Exception {
+ final CameraInfo cameraInfo = createCameraInfo(90,
+ CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, CameraSelector.LENS_FACING_BACK);
+
+ final PreviewView previewView = new PreviewView(mContext);
MeteringPointFactory factory = previewView.getMeteringPointFactory();
- MeteringPoint point = factory.createPoint(100, 100);
- assertThat(point.getX() >= 0f || point.getX() <= 1.0f);
- assertThat(point.getY() >= 0f || point.getY() <= 1.0f);
+ mInstrumentation.runOnMainSync(() -> {
+ setContentView(previewView);
+ mSurfaceRequest = createSurfaceRequest(cameraInfo);
+ Preview.SurfaceProvider surfaceProvider = previewView.createSurfaceProvider();
+ surfaceProvider.onSurfaceRequested(mSurfaceRequest);
+ });
+
+ changeViewSize(previewView, 1000, 1000);
+ MeteringPoint point1 = factory.createPoint(100, 100);
+
+ changeViewSize(previewView, 500, 400);
+
+ MeteringPoint point2 = factory.createPoint(100, 100);
+
+ assertPointIsValid(point1);
+ assertPointIsValid(point2);
+ // These points should be different because the layout is changed.
+ assertPointsAreDifferent(point1, point2);
+ }
+
+ private void changeViewSize(PreviewView previewView, int newWidth, int newHeight)
+ throws InterruptedException {
+ CountDownLatch latchToWaitForLayoutChange = new CountDownLatch(1);
+ mInstrumentation.runOnMainSync(() -> {
+ previewView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ if (previewView.getWidth() == newWidth
+ && previewView.getHeight() == newHeight) {
+ latchToWaitForLayoutChange.countDown();
+ previewView.removeOnLayoutChangeListener(this);
+ }
+ }
+ });
+ previewView.setLayoutParams(new FrameLayout.LayoutParams(newWidth, newHeight));
+ });
+
+ // Wait until the new layout is changed.
+ assertThat(latchToWaitForLayoutChange.await(1, TimeUnit.SECONDS)).isTrue();
+ }
+
+ @Test
+ public void meteringPointFactoryAutoAdjusted_whenScaleTypeChanged() throws Exception {
+ final CameraInfo cameraInfo = createCameraInfo(90,
+ CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, CameraSelector.LENS_FACING_BACK);
+
+ final PreviewView previewView = new PreviewView(mContext);
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
+
+ mInstrumentation.runOnMainSync(() -> {
+ setContentView(previewView);
+ mSurfaceRequest = createSurfaceRequest(cameraInfo);
+ Preview.SurfaceProvider surfaceProvider = previewView.createSurfaceProvider();
+ surfaceProvider.onSurfaceRequested(mSurfaceRequest);
+ });
+ // Surface resolution is 640x480 , set a different size for PreviewView.
+ changeViewSize(previewView, 800, 700);
+
+ previewView.setScaleType(PreviewView.ScaleType.FILL_CENTER);
+ MeteringPoint point1 = factory.createPoint(100, 100);
+
+ previewView.setScaleType(PreviewView.ScaleType.FIT_START);
+ MeteringPoint point2 = factory.createPoint(100, 100);
+
+ assertPointIsValid(point1);
+ assertPointIsValid(point2);
+ // These points should be different
+ assertPointsAreDifferent(point1, point2);
+ }
+
+ @Test
+ public void meteringPointFactoryAutoAdjusted_whenSurfaceRequestChanged() throws Exception {
+ final CameraInfo cameraInfo1 = createCameraInfo(90,
+ CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, CameraSelector.LENS_FACING_BACK);
+ final CameraInfo cameraInfo2 = createCameraInfo(270,
+ CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, CameraSelector.LENS_FACING_FRONT);
+
+ final PreviewView previewView = new PreviewView(mContext);
+ MeteringPointFactory factory = previewView.getMeteringPointFactory();
+
+ mInstrumentation.runOnMainSync(() -> {
+ setContentView(previewView);
+ mSurfaceRequest = createSurfaceRequest(cameraInfo1);
+ Preview.SurfaceProvider surfaceProvider = previewView.createSurfaceProvider();
+ surfaceProvider.onSurfaceRequested(mSurfaceRequest);
+ });
+
+ changeViewSize(previewView, 1000, 1000);
+
+ // get a MeteringPoint from a non-center point.
+ MeteringPoint point1 = factory.createPoint(100, 120);
+
+ mInstrumentation.runOnMainSync(() -> {
+ setContentView(previewView);
+ mSurfaceRequest = createSurfaceRequest(cameraInfo2);
+ Preview.SurfaceProvider surfaceProvider = previewView.createSurfaceProvider();
+ surfaceProvider.onSurfaceRequested(mSurfaceRequest);
+ });
+
+ MeteringPoint point2 = factory.createPoint(100, 120);
+
+ assertPointIsValid(point1);
+ assertPointIsValid(point2);
+ // These points should be different
+ assertPointsAreDifferent(point1, point2);
+ }
+
+ private void assertPointsAreDifferent(MeteringPoint point1, MeteringPoint point2) {
+ assertThat(point1.getX() != point2.getX() || point1.getY() != point2.getY()).isTrue();
+ }
+
+ private void waitForLayoutReady(PreviewView previewView) throws InterruptedException {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ previewView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ if (v.getWidth() > 0 && v.getHeight() > 0) {
+ countDownLatch.countDown();
+ previewView.removeOnLayoutChangeListener(this);
+ }
+ }
+ });
+ assertThat(countDownLatch.await(1, TimeUnit.SECONDS)).isTrue();
}
@Test
@UiThreadTest
- public void createMeteringPointFactory_previewViewWidthOrHeightIs0() {
+ public void meteringPointInvalid_whenPreviewViewWidthOrHeightIs0() {
final CameraInfo cameraInfo = createCameraInfo(90,
CameraInfo.IMPLEMENTATION_TYPE_CAMERA2, CameraSelector.LENS_FACING_BACK);
@@ -311,13 +459,17 @@
//Width and height is 0, but surface is requested,
//verifying the factory only creates invalid points.
MeteringPoint point = factory.createPoint(100, 100);
- assertThat(point.getX() < 0f || point.getX() > 1.0f);
- assertThat(point.getY() < 0f || point.getY() > 1.0f);
+ assertPointIsInvalid(point);
+ }
+
+ private void assertPointIsInvalid(MeteringPoint point) {
+ assertThat(point.getX() < 0f || point.getX() > 1.0f).isTrue();
+ assertThat(point.getY() < 0f || point.getY() > 1.0f).isTrue();
}
@Test
@UiThreadTest
- public void createMeteringPointFactory_beforeCreatingSurfaceProvider() {
+ public void meteringPointInvalid_beforeCreatingSurfaceProvider() {
final PreviewView previewView = new PreviewView(mContext);
// make PreviewView.getWidth() getHeight not 0.
setContentView(previewView);
@@ -325,8 +477,7 @@
//verifying the factory only creates invalid points.
MeteringPoint point = factory.createPoint(100, 100);
- assertThat(point.getX() < 0f || point.getX() > 1.0f);
- assertThat(point.getY() < 0f || point.getY() > 1.0f);
+ assertPointIsInvalid(point);
}
@Test
diff --git a/ui/ui-animation-core/OWNERS b/compose/animation/animation-core/OWNERS
similarity index 100%
rename from ui/ui-animation-core/OWNERS
rename to compose/animation/animation-core/OWNERS
diff --git a/ui/ui-animation-core/api/0.1.0-dev01.txt b/compose/animation/animation-core/api/0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev01.txt
rename to compose/animation/animation-core/api/0.1.0-dev01.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev02.txt b/compose/animation/animation-core/api/0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev02.txt
rename to compose/animation/animation-core/api/0.1.0-dev02.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev03.txt b/compose/animation/animation-core/api/0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev03.txt
rename to compose/animation/animation-core/api/0.1.0-dev03.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev04.txt b/compose/animation/animation-core/api/0.1.0-dev04.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev04.txt
rename to compose/animation/animation-core/api/0.1.0-dev04.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev05.txt b/compose/animation/animation-core/api/0.1.0-dev05.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev05.txt
rename to compose/animation/animation-core/api/0.1.0-dev05.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev06.txt b/compose/animation/animation-core/api/0.1.0-dev06.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev06.txt
rename to compose/animation/animation-core/api/0.1.0-dev06.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev07.txt b/compose/animation/animation-core/api/0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev07.txt
rename to compose/animation/animation-core/api/0.1.0-dev07.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev08.txt b/compose/animation/animation-core/api/0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev08.txt
rename to compose/animation/animation-core/api/0.1.0-dev08.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev09.txt b/compose/animation/animation-core/api/0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev09.txt
rename to compose/animation/animation-core/api/0.1.0-dev09.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev10.txt b/compose/animation/animation-core/api/0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev10.txt
rename to compose/animation/animation-core/api/0.1.0-dev10.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev11.txt b/compose/animation/animation-core/api/0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev11.txt
rename to compose/animation/animation-core/api/0.1.0-dev11.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev12.txt b/compose/animation/animation-core/api/0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev12.txt
rename to compose/animation/animation-core/api/0.1.0-dev12.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev14.txt b/compose/animation/animation-core/api/0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev14.txt
rename to compose/animation/animation-core/api/0.1.0-dev14.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev15.txt b/compose/animation/animation-core/api/0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev15.txt
rename to compose/animation/animation-core/api/0.1.0-dev15.txt
diff --git a/ui/ui-animation-core/api/0.1.0-dev16.txt b/compose/animation/animation-core/api/0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-animation-core/api/0.1.0-dev16.txt
rename to compose/animation/animation-core/api/0.1.0-dev16.txt
diff --git a/ui/ui-animation-core/api/api_lint.ignore b/compose/animation/animation-core/api/api_lint.ignore
similarity index 100%
rename from ui/ui-animation-core/api/api_lint.ignore
rename to compose/animation/animation-core/api/api_lint.ignore
diff --git a/ui/ui-animation-core/api/current.txt b/compose/animation/animation-core/api/current.txt
similarity index 100%
rename from ui/ui-animation-core/api/current.txt
rename to compose/animation/animation-core/api/current.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev01.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev01.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev01.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev02.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev02.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev02.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev03.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev03.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev03.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev04.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev04.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev04.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev04.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev05.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev05.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev05.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev05.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev06.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev06.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev06.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev06.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev07.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev07.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev07.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev08.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev08.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev08.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev09.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev09.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev09.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev10.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev10.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev10.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev11.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev11.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev11.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev12.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev12.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev12.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev14.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev14.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev14.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev15.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev15.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev15.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev16.txt b/compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_0.1.0-dev16.txt
rename to compose/animation/animation-core/api/public_plus_experimental_0.1.0-dev16.txt
diff --git a/ui/ui-animation-core/api/public_plus_experimental_current.txt b/compose/animation/animation-core/api/public_plus_experimental_current.txt
similarity index 100%
rename from ui/ui-animation-core/api/public_plus_experimental_current.txt
rename to compose/animation/animation-core/api/public_plus_experimental_current.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev01.txt b/compose/animation/animation-core/api/res-0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev01.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev01.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev02.txt b/compose/animation/animation-core/api/res-0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev02.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev02.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev03.txt b/compose/animation/animation-core/api/res-0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev03.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev03.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev04.txt b/compose/animation/animation-core/api/res-0.1.0-dev04.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev04.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev04.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev05.txt b/compose/animation/animation-core/api/res-0.1.0-dev05.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev05.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev05.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev06.txt b/compose/animation/animation-core/api/res-0.1.0-dev06.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev06.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev06.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev07.txt b/compose/animation/animation-core/api/res-0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev07.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev07.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev08.txt b/compose/animation/animation-core/api/res-0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev08.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev08.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev09.txt b/compose/animation/animation-core/api/res-0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev09.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev09.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev10.txt b/compose/animation/animation-core/api/res-0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev10.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev10.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev11.txt b/compose/animation/animation-core/api/res-0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev11.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev11.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev12.txt b/compose/animation/animation-core/api/res-0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev12.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev12.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev14.txt b/compose/animation/animation-core/api/res-0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev14.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev14.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev15.txt b/compose/animation/animation-core/api/res-0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev15.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev15.txt
diff --git a/ui/ui-animation-core/api/res-0.1.0-dev16.txt b/compose/animation/animation-core/api/res-0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-0.1.0-dev16.txt
rename to compose/animation/animation-core/api/res-0.1.0-dev16.txt
diff --git a/ui/ui-animation-core/api/res-current.txt b/compose/animation/animation-core/api/res-current.txt
similarity index 100%
rename from ui/ui-animation-core/api/res-current.txt
rename to compose/animation/animation-core/api/res-current.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev01.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev01.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev01.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev02.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev02.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev02.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev03.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev03.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev03.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev04.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev04.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev04.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev04.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev05.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev05.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev05.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev05.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev06.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev06.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev06.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev06.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev07.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev07.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev07.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev08.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev08.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev08.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev09.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev09.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev09.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev10.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev10.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev10.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev11.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev11.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev11.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev12.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev12.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev12.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev14.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev14.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev14.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev15.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev15.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev15.txt
diff --git a/ui/ui-animation-core/api/restricted_0.1.0-dev16.txt b/compose/animation/animation-core/api/restricted_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_0.1.0-dev16.txt
rename to compose/animation/animation-core/api/restricted_0.1.0-dev16.txt
diff --git a/ui/ui-animation-core/api/restricted_current.txt b/compose/animation/animation-core/api/restricted_current.txt
similarity index 100%
rename from ui/ui-animation-core/api/restricted_current.txt
rename to compose/animation/animation-core/api/restricted_current.txt
diff --git a/ui/ui-animation-core/build.gradle b/compose/animation/animation-core/build.gradle
similarity index 96%
rename from ui/ui-animation-core/build.gradle
rename to compose/animation/animation-core/build.gradle
index 39aadb2..03dedb5 100644
--- a/ui/ui-animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -48,7 +48,6 @@
implementation (KOTLIN_STDLIB)
}
desktopMain.dependencies {
- implementation project(":compose:runtime:runtime-dispatch")
implementation (KOTLIN_STDLIB)
}
diff --git a/ui/ui-animation-core/samples/build.gradle b/compose/animation/animation-core/samples/build.gradle
similarity index 100%
rename from ui/ui-animation-core/samples/build.gradle
rename to compose/animation/animation-core/samples/build.gradle
diff --git a/ui/ui-animation-core/samples/src/main/AndroidManifest.xml b/compose/animation/animation-core/samples/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-animation-core/samples/src/main/AndroidManifest.xml
rename to compose/animation/animation-core/samples/src/main/AndroidManifest.xml
diff --git a/ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
similarity index 99%
rename from ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
rename to compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
index bcb4aea..186026b 100644
--- a/ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/KeyframesBuilderSample.kt
@@ -16,12 +16,12 @@
package androidx.compose.animation.core.samples
+import androidx.annotation.Sampled
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.KeyframesSpec
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.LinearOutSlowInEasing
import androidx.compose.animation.core.keyframes
-import androidx.annotation.Sampled
import androidx.compose.ui.unit.Position
import androidx.compose.ui.unit.dp
diff --git a/ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionDefinitionSamples.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionDefinitionSamples.kt
similarity index 99%
rename from ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionDefinitionSamples.kt
rename to compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionDefinitionSamples.kt
index 189b7af..ca07aac 100644
--- a/ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionDefinitionSamples.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionDefinitionSamples.kt
@@ -16,12 +16,12 @@
package androidx.compose.animation.core.samples
+import androidx.annotation.Sampled
import androidx.compose.animation.core.FloatPropKey
import androidx.compose.animation.core.InterruptionHandling
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.transitionDefinition
-import androidx.annotation.Sampled
private val radius = FloatPropKey()
private val alpha = FloatPropKey()
diff --git a/ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSpecSamples.kt b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSpecSamples.kt
similarity index 99%
rename from ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSpecSamples.kt
rename to compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSpecSamples.kt
index c9e198f6..4f3e7c0 100644
--- a/ui/ui-animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSpecSamples.kt
+++ b/compose/animation/animation-core/samples/src/main/java/androidx/compose/animation/core/samples/TransitionSpecSamples.kt
@@ -16,6 +16,7 @@
package androidx.compose.animation.core.samples
+import androidx.annotation.Sampled
import androidx.compose.animation.core.FloatPropKey
import androidx.compose.animation.core.InterruptionHandling
import androidx.compose.animation.core.LinearEasing
@@ -23,7 +24,6 @@
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.transitionDefinition
import androidx.compose.animation.core.tween
-import androidx.annotation.Sampled
enum class ButtonState {
Released,
diff --git a/ui/ui-animation-core/src/androidMain/AndroidManifest.xml b/compose/animation/animation-core/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from ui/ui-animation-core/src/androidMain/AndroidManifest.xml
rename to compose/animation/animation-core/src/androidMain/AndroidManifest.xml
diff --git a/ui/ui-animation-core/src/androidMain/kotlin/androidx/compose/animation/core/AndroidAnimationClock.kt b/compose/animation/animation-core/src/androidMain/kotlin/androidx/compose/animation/core/AndroidAnimationClock.kt
similarity index 100%
rename from ui/ui-animation-core/src/androidMain/kotlin/androidx/compose/animation/core/AndroidAnimationClock.kt
rename to compose/animation/animation-core/src/androidMain/kotlin/androidx/compose/animation/core/AndroidAnimationClock.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimatedValue.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimatedValue.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimatedValue.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimatedValue.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Animation.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClock.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClock.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClock.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClock.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClockObservable.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClockObservable.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClockObservable.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationClockObservable.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
similarity index 99%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
index 16966c6..97cdf37 100644
--- a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationSpec.kt
@@ -17,6 +17,7 @@
package androidx.compose.animation.core
import androidx.compose.animation.core.AnimationConstants.DefaultDurationMillis
+import androidx.compose.animation.core.KeyframesSpec.KeyframesSpecConfig
import androidx.compose.runtime.Immutable
import androidx.compose.ui.util.annotation.IntRange
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationVectors.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationVectors.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationVectors.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/AnimationVectors.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ComplexDouble.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ComplexDouble.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ComplexDouble.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ComplexDouble.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/DynamicTargetAnimation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/DynamicTargetAnimation.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/DynamicTargetAnimation.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/DynamicTargetAnimation.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Easing.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatAnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatAnimationSpec.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatAnimationSpec.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatAnimationSpec.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatDecayAnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatDecayAnimationSpec.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatDecayAnimationSpec.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/FloatDecayAnimationSpec.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/PropKey.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/PropKey.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/PropKey.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/PropKey.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringEstimation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringEstimation.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringEstimation.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringEstimation.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringSimulation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringSimulation.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringSimulation.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringSimulation.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ToolingGlue.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ToolingGlue.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ToolingGlue.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ToolingGlue.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionAnimation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionAnimation.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionAnimation.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionAnimation.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionDefinition.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionDefinition.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionDefinition.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionDefinition.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionState.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionState.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionState.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/TransitionState.kt
diff --git a/ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
similarity index 100%
rename from ui/ui-animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
rename to compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/VectorizedAnimationSpec.kt
diff --git a/ui/ui-animation-core/src/desktopMain/kotlin/androidx/compose/animation/core/DefaultAnimationClock.kt b/compose/animation/animation-core/src/desktopMain/kotlin/androidx/compose/animation/core/DefaultAnimationClock.kt
similarity index 81%
rename from ui/ui-animation-core/src/desktopMain/kotlin/androidx/compose/animation/core/DefaultAnimationClock.kt
rename to compose/animation/animation-core/src/desktopMain/kotlin/androidx/compose/animation/core/DefaultAnimationClock.kt
index a9dca06..eef5dd2 100644
--- a/ui/ui-animation-core/src/desktopMain/kotlin/androidx/compose/animation/core/DefaultAnimationClock.kt
+++ b/compose/animation/animation-core/src/desktopMain/kotlin/androidx/compose/animation/core/DefaultAnimationClock.kt
@@ -38,23 +38,20 @@
}
override fun subscribe(observer: AnimationClockObserver) {
+ if (!scheduled) {
+ dispatcher.scheduleCallbackWithDelay(delay, ::frameCallback)
+ scheduled = true
+ }
super.subscribe(observer)
- scheduleIfNeeded()
}
override fun dispatchTime(frameTimeMillis: Long) {
super.dispatchTime(frameTimeMillis)
- scheduleIfNeeded()
- }
-
- private fun scheduleIfNeeded() {
- when {
- scheduled -> return
- !hasObservers() -> return
- else -> {
- scheduled = true
- dispatcher.scheduleCallbackWithDelay(delay, ::frameCallback)
- }
+ scheduled = if (hasObservers()) {
+ dispatcher.scheduleCallbackWithDelay(delay, ::frameCallback)
+ true
+ } else {
+ false
}
}
}
\ No newline at end of file
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimatedValueTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimatedValueTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimatedValueTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimatedValueTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationClockTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationClockTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationClockTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationClockTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationTestUtils.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationTestUtils.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationTestUtils.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationTestUtils.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationVectorTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationVectorTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/AnimationVectorTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/AnimationVectorTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/DecayAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/DecayAnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/DecayAnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/DecayAnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/EasingTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/EasingTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/EasingTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/EasingTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/KeyframeAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/KeyframeAnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/KeyframeAnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/KeyframeAnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/MotionTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/MotionTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/MotionTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/MotionTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/PhysicsAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/PhysicsAnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/PhysicsAnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/PhysicsAnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/RepeatableAnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/SnapAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SnapAnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/SnapAnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SnapAnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/SpringEstimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SpringEstimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/SpringEstimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SpringEstimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/ToolingGlueTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/ToolingGlueTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/ToolingGlueTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/ToolingGlueTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TransitionAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TransitionAnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TransitionAnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TransitionAnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TransitionDefinitionTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TransitionDefinitionTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TransitionDefinitionTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TransitionDefinitionTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TweenAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TweenAnimationTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TweenAnimationTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TweenAnimationTest.kt
diff --git a/ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TypeConverterTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TypeConverterTest.kt
similarity index 100%
rename from ui/ui-animation-core/src/test/java/androidx/compose/animation/core/TypeConverterTest.kt
rename to compose/animation/animation-core/src/test/java/androidx/compose/animation/core/TypeConverterTest.kt
diff --git a/ui/ui-animation/OWNERS b/compose/animation/animation/OWNERS
similarity index 100%
rename from ui/ui-animation/OWNERS
rename to compose/animation/animation/OWNERS
diff --git a/ui/ui-animation/api/0.1.0-dev01.txt b/compose/animation/animation/api/0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev01.txt
rename to compose/animation/animation/api/0.1.0-dev01.txt
diff --git a/ui/ui-animation/api/0.1.0-dev02.txt b/compose/animation/animation/api/0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev02.txt
rename to compose/animation/animation/api/0.1.0-dev02.txt
diff --git a/ui/ui-animation/api/0.1.0-dev03.txt b/compose/animation/animation/api/0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev03.txt
rename to compose/animation/animation/api/0.1.0-dev03.txt
diff --git a/ui/ui-animation/api/0.1.0-dev04.txt b/compose/animation/animation/api/0.1.0-dev04.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev04.txt
rename to compose/animation/animation/api/0.1.0-dev04.txt
diff --git a/ui/ui-animation/api/0.1.0-dev05.txt b/compose/animation/animation/api/0.1.0-dev05.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev05.txt
rename to compose/animation/animation/api/0.1.0-dev05.txt
diff --git a/ui/ui-animation/api/0.1.0-dev06.txt b/compose/animation/animation/api/0.1.0-dev06.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev06.txt
rename to compose/animation/animation/api/0.1.0-dev06.txt
diff --git a/ui/ui-animation/api/0.1.0-dev07.txt b/compose/animation/animation/api/0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev07.txt
rename to compose/animation/animation/api/0.1.0-dev07.txt
diff --git a/ui/ui-animation/api/0.1.0-dev08.txt b/compose/animation/animation/api/0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev08.txt
rename to compose/animation/animation/api/0.1.0-dev08.txt
diff --git a/ui/ui-animation/api/0.1.0-dev09.txt b/compose/animation/animation/api/0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev09.txt
rename to compose/animation/animation/api/0.1.0-dev09.txt
diff --git a/ui/ui-animation/api/0.1.0-dev10.txt b/compose/animation/animation/api/0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev10.txt
rename to compose/animation/animation/api/0.1.0-dev10.txt
diff --git a/ui/ui-animation/api/0.1.0-dev11.txt b/compose/animation/animation/api/0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev11.txt
rename to compose/animation/animation/api/0.1.0-dev11.txt
diff --git a/ui/ui-animation/api/0.1.0-dev12.txt b/compose/animation/animation/api/0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev12.txt
rename to compose/animation/animation/api/0.1.0-dev12.txt
diff --git a/ui/ui-animation/api/0.1.0-dev14.txt b/compose/animation/animation/api/0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev14.txt
rename to compose/animation/animation/api/0.1.0-dev14.txt
diff --git a/ui/ui-animation/api/0.1.0-dev15.txt b/compose/animation/animation/api/0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev15.txt
rename to compose/animation/animation/api/0.1.0-dev15.txt
diff --git a/ui/ui-animation/api/0.1.0-dev16.txt b/compose/animation/animation/api/0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-animation/api/0.1.0-dev16.txt
rename to compose/animation/animation/api/0.1.0-dev16.txt
diff --git a/ui/ui-animation/api/api_lint.ignore b/compose/animation/animation/api/api_lint.ignore
similarity index 100%
rename from ui/ui-animation/api/api_lint.ignore
rename to compose/animation/animation/api/api_lint.ignore
diff --git a/ui/ui-animation/api/current.txt b/compose/animation/animation/api/current.txt
similarity index 100%
rename from ui/ui-animation/api/current.txt
rename to compose/animation/animation/api/current.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev01.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev01.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev01.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev02.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev02.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev02.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev03.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev03.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev03.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev04.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev04.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev04.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev04.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev05.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev05.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev05.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev05.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev06.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev06.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev06.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev06.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev07.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev07.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev07.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev08.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev08.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev08.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev09.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev09.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev09.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev10.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev10.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev10.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev11.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev11.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev11.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev12.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev12.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev12.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev14.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev14.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev14.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev15.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev15.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev15.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_0.1.0-dev16.txt b/compose/animation/animation/api/public_plus_experimental_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_0.1.0-dev16.txt
rename to compose/animation/animation/api/public_plus_experimental_0.1.0-dev16.txt
diff --git a/ui/ui-animation/api/public_plus_experimental_current.txt b/compose/animation/animation/api/public_plus_experimental_current.txt
similarity index 100%
rename from ui/ui-animation/api/public_plus_experimental_current.txt
rename to compose/animation/animation/api/public_plus_experimental_current.txt
diff --git a/ui/ui-animation/api/res-0.1.0-dev01.txt b/compose/animation/animation/api/res-0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation/api/res-0.1.0-dev01.txt
rename to compose/animation/animation/api/res-0.1.0-dev01.txt
diff --git a/ui/ui-animation/api/res-0.1.0-dev02.txt b/compose/animation/animation/api/res-0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation/api/res-0.1.0-dev02.txt
rename to compose/animation/animation/api/res-0.1.0-dev02.txt
diff --git a/ui/ui-animation/api/res-0.1.0-dev03.txt b/compose/animation/animation/api/res-0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation/api/res-0.1.0-dev03.txt
rename to compose/animation/animation/api/res-0.1.0-dev03.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev04.txt b/compose/animation/animation/api/res-0.1.0-dev04.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev04.txt
copy to compose/animation/animation/api/res-0.1.0-dev04.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev05.txt b/compose/animation/animation/api/res-0.1.0-dev05.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev05.txt
copy to compose/animation/animation/api/res-0.1.0-dev05.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev06.txt b/compose/animation/animation/api/res-0.1.0-dev06.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev06.txt
copy to compose/animation/animation/api/res-0.1.0-dev06.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev07.txt b/compose/animation/animation/api/res-0.1.0-dev07.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev07.txt
copy to compose/animation/animation/api/res-0.1.0-dev07.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev08.txt b/compose/animation/animation/api/res-0.1.0-dev08.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev08.txt
copy to compose/animation/animation/api/res-0.1.0-dev08.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev09.txt b/compose/animation/animation/api/res-0.1.0-dev09.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev09.txt
copy to compose/animation/animation/api/res-0.1.0-dev09.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev10.txt b/compose/animation/animation/api/res-0.1.0-dev10.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev10.txt
copy to compose/animation/animation/api/res-0.1.0-dev10.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev11.txt b/compose/animation/animation/api/res-0.1.0-dev11.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev11.txt
copy to compose/animation/animation/api/res-0.1.0-dev11.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev12.txt b/compose/animation/animation/api/res-0.1.0-dev12.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev12.txt
copy to compose/animation/animation/api/res-0.1.0-dev12.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev14.txt b/compose/animation/animation/api/res-0.1.0-dev14.txt
similarity index 100%
copy from compose/compose-runtime/api/res-0.1.0-dev14.txt
copy to compose/animation/animation/api/res-0.1.0-dev14.txt
diff --git a/compose/compose-dispatch/api/res-0.1.0-dev15.txt b/compose/animation/animation/api/res-0.1.0-dev15.txt
similarity index 100%
copy from compose/compose-dispatch/api/res-0.1.0-dev15.txt
copy to compose/animation/animation/api/res-0.1.0-dev15.txt
diff --git a/compose/compose-dispatch/api/res-0.1.0-dev16.txt b/compose/animation/animation/api/res-0.1.0-dev16.txt
similarity index 100%
copy from compose/compose-dispatch/api/res-0.1.0-dev16.txt
copy to compose/animation/animation/api/res-0.1.0-dev16.txt
diff --git a/compose/compose-dispatch/api/res-current.txt b/compose/animation/animation/api/res-current.txt
similarity index 100%
copy from compose/compose-dispatch/api/res-current.txt
copy to compose/animation/animation/api/res-current.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev01.txt b/compose/animation/animation/api/restricted_0.1.0-dev01.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev01.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev01.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev02.txt b/compose/animation/animation/api/restricted_0.1.0-dev02.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev02.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev02.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev03.txt b/compose/animation/animation/api/restricted_0.1.0-dev03.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev03.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev03.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev04.txt b/compose/animation/animation/api/restricted_0.1.0-dev04.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev04.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev04.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev05.txt b/compose/animation/animation/api/restricted_0.1.0-dev05.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev05.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev05.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev06.txt b/compose/animation/animation/api/restricted_0.1.0-dev06.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev06.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev06.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev07.txt b/compose/animation/animation/api/restricted_0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev07.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev07.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev08.txt b/compose/animation/animation/api/restricted_0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev08.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev08.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev09.txt b/compose/animation/animation/api/restricted_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev09.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev09.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev10.txt b/compose/animation/animation/api/restricted_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev10.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev10.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev11.txt b/compose/animation/animation/api/restricted_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev11.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev11.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev12.txt b/compose/animation/animation/api/restricted_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev12.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev12.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev14.txt b/compose/animation/animation/api/restricted_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev14.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev14.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev15.txt b/compose/animation/animation/api/restricted_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev15.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev15.txt
diff --git a/ui/ui-animation/api/restricted_0.1.0-dev16.txt b/compose/animation/animation/api/restricted_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_0.1.0-dev16.txt
rename to compose/animation/animation/api/restricted_0.1.0-dev16.txt
diff --git a/ui/ui-animation/api/restricted_current.txt b/compose/animation/animation/api/restricted_current.txt
similarity index 100%
rename from ui/ui-animation/api/restricted_current.txt
rename to compose/animation/animation/api/restricted_current.txt
diff --git a/ui/ui-animation/build.gradle b/compose/animation/animation/build.gradle
similarity index 100%
rename from ui/ui-animation/build.gradle
rename to compose/animation/animation/build.gradle
diff --git a/ui/ui-animation/integration-tests/animation-demos/build.gradle b/compose/animation/animation/integration-tests/animation-demos/build.gradle
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/build.gradle
rename to compose/animation/animation/integration-tests/animation-demos/build.gradle
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/AndroidManifest.xml b/compose/animation/animation/integration-tests/animation-demos/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/AndroidManifest.xml
rename to compose/animation/animation/integration-tests/animation-demos/src/main/AndroidManifest.xml
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatableSeekBarDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatableSeekBarDemo.kt
similarity index 99%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatableSeekBarDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatableSeekBarDemo.kt
index 896feae..3cf03c9 100644
--- a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatableSeekBarDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatableSeekBarDemo.kt
@@ -16,33 +16,33 @@
package androidx.compose.animation.demos
+import androidx.compose.animation.animatedFloat
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.FloatPropKey
import androidx.compose.animation.core.ManualAnimationClock
import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.transitionDefinition
import androidx.compose.animation.core.tween
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Providers
-import androidx.compose.runtime.remember
import androidx.compose.animation.transition
-import androidx.compose.animation.animatedFloat
-import androidx.compose.ui.platform.AnimationClockAmbient
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.gesture.DragObserver
-import androidx.compose.ui.gesture.pressIndicatorGestureFilter
-import androidx.compose.ui.gesture.rawDragGestureFilter
import androidx.compose.foundation.Box
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Text
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.preferredHeight
import androidx.compose.foundation.layout.preferredSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Providers
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.gesture.DragObserver
+import androidx.compose.ui.gesture.pressIndicatorGestureFilter
+import androidx.compose.ui.gesture.rawDragGestureFilter
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.AnimationClockAmbient
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
similarity index 99%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
index 4c9869a..2e16ef8 100644
--- a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
@@ -16,8 +16,8 @@
package androidx.compose.animation.demos
+import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.tween
-import androidx.compose.runtime.Composable
import androidx.compose.foundation.Box
import androidx.compose.foundation.Text
import androidx.compose.foundation.background
@@ -33,14 +33,14 @@
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Button
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.animation.animateContentSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.material.Button
import androidx.compose.ui.unit.dp
@Composable
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/MultiDimensionalAnimationDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RepeatedRotationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RepeatedRotationDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RepeatedRotationDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/RepeatedRotationDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SingleValueAnimationDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
similarity index 99%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
index ac679a9..d1af27e 100644
--- a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
@@ -18,25 +18,25 @@
import android.os.Handler
import android.os.Looper
+import androidx.compose.animation.ColorPropKey
import androidx.compose.animation.core.FloatPropKey
import androidx.compose.animation.core.TransitionState
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.transitionDefinition
import androidx.compose.animation.core.tween
+import androidx.compose.animation.transition
+import androidx.compose.foundation.Box
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
-import androidx.compose.animation.ColorPropKey
-import androidx.compose.animation.transition
import androidx.compose.ui.Modifier
-import androidx.compose.foundation.Box
-import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.background
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
-import androidx.compose.foundation.layout.fillMaxSize
@Composable
fun StateAnimationWithInterruptionsDemo() {
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
diff --git a/ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
similarity index 100%
rename from ui/ui-animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
rename to compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
diff --git a/ui/ui-animation/samples/build.gradle b/compose/animation/animation/samples/build.gradle
similarity index 100%
rename from ui/ui-animation/samples/build.gradle
rename to compose/animation/animation/samples/build.gradle
diff --git a/ui/ui-animation/samples/src/main/AndroidManifest.xml b/compose/animation/animation/samples/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-animation/samples/src/main/AndroidManifest.xml
rename to compose/animation/animation/samples/src/main/AndroidManifest.xml
diff --git a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
similarity index 100%
rename from ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
rename to compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
diff --git a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
similarity index 100%
rename from ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
rename to compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
diff --git a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
similarity index 99%
rename from ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
rename to compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
index f1daa01..17c1672 100644
--- a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
@@ -17,7 +17,7 @@
package androidx.compose.animation.samples
import androidx.annotation.Sampled
-import androidx.compose.runtime.Composable
+import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.Box
import androidx.compose.foundation.Text
import androidx.compose.foundation.background
@@ -26,11 +26,11 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.animation.animateContentSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
diff --git a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/CrossfadeSample.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/CrossfadeSample.kt
similarity index 99%
rename from ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/CrossfadeSample.kt
rename to compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/CrossfadeSample.kt
index 48a7bcf..7987992 100644
--- a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/CrossfadeSample.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/CrossfadeSample.kt
@@ -17,9 +17,9 @@
package androidx.compose.animation.samples
import androidx.annotation.Sampled
-import androidx.compose.runtime.Composable
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.Text
+import androidx.compose.runtime.Composable
@Sampled
@Composable
diff --git a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
similarity index 99%
rename from ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
rename to compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
index 5a0c96c..0dc02f8 100644
--- a/ui/ui-animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
@@ -16,17 +16,17 @@
package androidx.compose.animation.samples
-import androidx.compose.animation.core.transitionDefinition
import androidx.annotation.Sampled
-import androidx.compose.runtime.Composable
import androidx.compose.animation.ColorPropKey
import androidx.compose.animation.DpPropKey
+import androidx.compose.animation.core.transitionDefinition
import androidx.compose.animation.transition
-import androidx.compose.ui.Modifier
import androidx.compose.foundation.Box
import androidx.compose.foundation.background
-import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.layout.preferredSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
private enum class State {
diff --git a/ui/ui-animation/src/androidAndroidTest/AndroidManifest.xml b/compose/animation/animation/src/androidAndroidTest/AndroidManifest.xml
similarity index 100%
rename from ui/ui-animation/src/androidAndroidTest/AndroidManifest.xml
rename to compose/animation/animation/src/androidAndroidTest/AndroidManifest.xml
diff --git a/ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
similarity index 100%
rename from ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
rename to compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
diff --git a/ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
similarity index 100%
rename from ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
rename to compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimationModifierTest.kt
diff --git a/ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/CrossfadeTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/CrossfadeTest.kt
similarity index 100%
rename from ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/CrossfadeTest.kt
rename to compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/CrossfadeTest.kt
diff --git a/ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
similarity index 100%
rename from ui/ui-animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
rename to compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
diff --git a/ui/ui-animation/src/androidMain/AndroidManifest.xml b/compose/animation/animation/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from ui/ui-animation/src/androidMain/AndroidManifest.xml
rename to compose/animation/animation/src/androidMain/AndroidManifest.xml
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedValueEffects.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedValueEffects.kt
similarity index 99%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedValueEffects.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedValueEffects.kt
index 477cc04..986f12f 100644
--- a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedValueEffects.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedValueEffects.kt
@@ -30,8 +30,8 @@
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.structuralEqualityPolicy
-import androidx.compose.ui.platform.AnimationClockAmbient
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.AnimationClockAmbient
/**
* The animatedValue effect creates an [AnimatedValue] and positionally memoizes it. When the
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
similarity index 100%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
similarity index 99%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
index 3d23617..e5ec767 100644
--- a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
@@ -23,14 +23,14 @@
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.spring
import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.AnimationClockAmbient
-import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.LayoutModifier
import androidx.compose.ui.Measurable
import androidx.compose.ui.MeasureScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.platform.AnimationClockAmbient
+import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
/**
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
similarity index 99%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
index 27cf621..21df8cf 100644
--- a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
@@ -20,6 +20,7 @@
import androidx.compose.animation.core.AnimationEndReason
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.Stack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.invalidate
import androidx.compose.runtime.key
@@ -27,7 +28,6 @@
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawOpacity
-import androidx.compose.foundation.layout.Stack
import androidx.compose.ui.util.fastForEach
/**
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/DisposableAnimationClock.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/DisposableAnimationClock.kt
similarity index 100%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/DisposableAnimationClock.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/DisposableAnimationClock.kt
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
similarity index 100%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
similarity index 97%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
index 6bb04b6..0360f16 100644
--- a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
@@ -20,8 +20,6 @@
import androidx.compose.animation.core.TransitionDefinition
import androidx.compose.animation.core.TransitionState
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.AnimationClockAmbient
/**
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
similarity index 100%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
similarity index 99%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
index 2a814e5..f0aaef8 100644
--- a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
@@ -26,11 +26,11 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.onCommit
import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.AnimationClockAmbient
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.platform.AnimationClockAmbient
import androidx.compose.ui.unit.Bounds
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
diff --git a/ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/Transition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Transition.kt
similarity index 100%
rename from ui/ui-animation/src/commonMain/kotlin/androidx/compose/animation/Transition.kt
rename to compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Transition.kt
diff --git a/ui/ui-animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
similarity index 99%
rename from ui/ui-animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
rename to compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
index a13e287..7bdf8c34 100644
--- a/ui/ui-animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
+++ b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
@@ -19,10 +19,10 @@
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.AnimationVector4D
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.colorspace.ColorSpaces
-import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import junit.framework.TestCase.assertEquals
diff --git a/ui/ui-animation/src/test/kotlin/androidx/compose/animation/DisposableAnimationClockTest.kt b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/DisposableAnimationClockTest.kt
similarity index 100%
rename from ui/ui-animation/src/test/kotlin/androidx/compose/animation/DisposableAnimationClockTest.kt
rename to compose/animation/animation/src/test/kotlin/androidx/compose/animation/DisposableAnimationClockTest.kt
diff --git a/ui/ui-animation/src/test/kotlin/androidx/compose/animation/PropertyKeyTest.kt b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/PropertyKeyTest.kt
similarity index 100%
rename from ui/ui-animation/src/test/kotlin/androidx/compose/animation/PropertyKeyTest.kt
rename to compose/animation/animation/src/test/kotlin/androidx/compose/animation/PropertyKeyTest.kt
diff --git a/compose/animation/placeholder.txt b/compose/animation/placeholder.txt
deleted file mode 100644
index b8f7c1a..0000000
--- a/compose/animation/placeholder.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This file exists to make sure the directory this is in gets created by git, so that
-settings.gradle can point to this directory and not complain about it missing.
-
-TODO: b/160233169 remove this file once the directory structure is migrated from ui/ to here.
diff --git a/compose/runtime/placeholder.txt b/compose/runtime/placeholder.txt
deleted file mode 100644
index b8f7c1a..0000000
--- a/compose/runtime/placeholder.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This file exists to make sure the directory this is in gets created by git, so that
-settings.gradle can point to this directory and not complain about it missing.
-
-TODO: b/160233169 remove this file once the directory structure is migrated from ui/ to here.
diff --git a/compose/compose-dispatch/OWNERS b/compose/runtime/runtime-dispatch/OWNERS
similarity index 100%
rename from compose/compose-dispatch/OWNERS
rename to compose/runtime/runtime-dispatch/OWNERS
diff --git a/compose/compose-dispatch/api/0.1.0-dev15.txt b/compose/runtime/runtime-dispatch/api/0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-dispatch/api/0.1.0-dev15.txt
rename to compose/runtime/runtime-dispatch/api/0.1.0-dev15.txt
diff --git a/compose/compose-dispatch/api/0.1.0-dev16.txt b/compose/runtime/runtime-dispatch/api/0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-dispatch/api/0.1.0-dev16.txt
rename to compose/runtime/runtime-dispatch/api/0.1.0-dev16.txt
diff --git a/compose/compose-dispatch/api/current.txt b/compose/runtime/runtime-dispatch/api/current.txt
similarity index 100%
rename from compose/compose-dispatch/api/current.txt
rename to compose/runtime/runtime-dispatch/api/current.txt
diff --git a/compose/compose-dispatch/api/public_plus_experimental_0.1.0-dev15.txt b/compose/runtime/runtime-dispatch/api/public_plus_experimental_0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-dispatch/api/public_plus_experimental_0.1.0-dev15.txt
rename to compose/runtime/runtime-dispatch/api/public_plus_experimental_0.1.0-dev15.txt
diff --git a/compose/compose-dispatch/api/public_plus_experimental_0.1.0-dev16.txt b/compose/runtime/runtime-dispatch/api/public_plus_experimental_0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-dispatch/api/public_plus_experimental_0.1.0-dev16.txt
rename to compose/runtime/runtime-dispatch/api/public_plus_experimental_0.1.0-dev16.txt
diff --git a/compose/compose-dispatch/api/public_plus_experimental_current.txt b/compose/runtime/runtime-dispatch/api/public_plus_experimental_current.txt
similarity index 100%
rename from compose/compose-dispatch/api/public_plus_experimental_current.txt
rename to compose/runtime/runtime-dispatch/api/public_plus_experimental_current.txt
diff --git a/compose/compose-dispatch/api/res-0.1.0-dev15.txt b/compose/runtime/runtime-dispatch/api/res-0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-dispatch/api/res-0.1.0-dev15.txt
rename to compose/runtime/runtime-dispatch/api/res-0.1.0-dev15.txt
diff --git a/compose/compose-dispatch/api/res-0.1.0-dev16.txt b/compose/runtime/runtime-dispatch/api/res-0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-dispatch/api/res-0.1.0-dev16.txt
rename to compose/runtime/runtime-dispatch/api/res-0.1.0-dev16.txt
diff --git a/compose/compose-dispatch/api/res-current.txt b/compose/runtime/runtime-dispatch/api/res-current.txt
similarity index 100%
rename from compose/compose-dispatch/api/res-current.txt
rename to compose/runtime/runtime-dispatch/api/res-current.txt
diff --git a/compose/compose-dispatch/api/restricted_0.1.0-dev15.txt b/compose/runtime/runtime-dispatch/api/restricted_0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-dispatch/api/restricted_0.1.0-dev15.txt
rename to compose/runtime/runtime-dispatch/api/restricted_0.1.0-dev15.txt
diff --git a/compose/compose-dispatch/api/restricted_0.1.0-dev16.txt b/compose/runtime/runtime-dispatch/api/restricted_0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-dispatch/api/restricted_0.1.0-dev16.txt
rename to compose/runtime/runtime-dispatch/api/restricted_0.1.0-dev16.txt
diff --git a/compose/compose-dispatch/api/restricted_current.txt b/compose/runtime/runtime-dispatch/api/restricted_current.txt
similarity index 100%
rename from compose/compose-dispatch/api/restricted_current.txt
rename to compose/runtime/runtime-dispatch/api/restricted_current.txt
diff --git a/compose/compose-dispatch/build.gradle b/compose/runtime/runtime-dispatch/build.gradle
similarity index 100%
rename from compose/compose-dispatch/build.gradle
rename to compose/runtime/runtime-dispatch/build.gradle
diff --git a/compose/compose-dispatch/src/androidAndroidTest/AndroidManifest.xml b/compose/runtime/runtime-dispatch/src/androidAndroidTest/AndroidManifest.xml
similarity index 100%
rename from compose/compose-dispatch/src/androidAndroidTest/AndroidManifest.xml
rename to compose/runtime/runtime-dispatch/src/androidAndroidTest/AndroidManifest.xml
diff --git a/compose/compose-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcherTest.kt b/compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcherTest.kt
similarity index 100%
rename from compose/compose-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcherTest.kt
rename to compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcherTest.kt
diff --git a/compose/compose-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/TestActivity.kt b/compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/TestActivity.kt
similarity index 100%
rename from compose/compose-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/TestActivity.kt
rename to compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/TestActivity.kt
diff --git a/compose/compose-dispatch/src/androidMain/AndroidManifest.xml b/compose/runtime/runtime-dispatch/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from compose/compose-dispatch/src/androidMain/AndroidManifest.xml
rename to compose/runtime/runtime-dispatch/src/androidMain/AndroidManifest.xml
diff --git a/compose/compose-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/ActualAndroid.kt b/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/ActualAndroid.kt
similarity index 100%
rename from compose/compose-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/ActualAndroid.kt
rename to compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/ActualAndroid.kt
diff --git a/compose/compose-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcher.kt b/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcher.kt
similarity index 100%
rename from compose/compose-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcher.kt
rename to compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcher.kt
diff --git a/compose/compose-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiFrameClock.kt b/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiFrameClock.kt
similarity index 100%
rename from compose/compose-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiFrameClock.kt
rename to compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiFrameClock.kt
diff --git a/compose/compose-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClock.kt b/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClock.kt
similarity index 100%
rename from compose/compose-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClock.kt
rename to compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClock.kt
diff --git a/compose/compose-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt b/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt
similarity index 100%
rename from compose/compose-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt
rename to compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt
diff --git a/compose/compose-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt b/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt
similarity index 100%
rename from compose/compose-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt
rename to compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt
diff --git a/compose/compose-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/ActualDesktop.kt b/compose/runtime/runtime-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/ActualDesktop.kt
similarity index 100%
rename from compose/compose-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/ActualDesktop.kt
rename to compose/runtime/runtime-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/ActualDesktop.kt
diff --git a/compose/compose-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/DesktopUiDispatcher.kt b/compose/runtime/runtime-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/DesktopUiDispatcher.kt
similarity index 100%
rename from compose/compose-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/DesktopUiDispatcher.kt
rename to compose/runtime/runtime-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/DesktopUiDispatcher.kt
diff --git a/ui/ui-livedata/OWNERS b/compose/runtime/runtime-livedata/OWNERS
similarity index 100%
rename from ui/ui-livedata/OWNERS
rename to compose/runtime/runtime-livedata/OWNERS
diff --git a/ui/ui-livedata/api/0.1.0-dev09.txt b/compose/runtime/runtime-livedata/api/0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-livedata/api/0.1.0-dev09.txt
rename to compose/runtime/runtime-livedata/api/0.1.0-dev09.txt
diff --git a/ui/ui-livedata/api/0.1.0-dev10.txt b/compose/runtime/runtime-livedata/api/0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-livedata/api/0.1.0-dev10.txt
rename to compose/runtime/runtime-livedata/api/0.1.0-dev10.txt
diff --git a/ui/ui-livedata/api/0.1.0-dev11.txt b/compose/runtime/runtime-livedata/api/0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-livedata/api/0.1.0-dev11.txt
rename to compose/runtime/runtime-livedata/api/0.1.0-dev11.txt
diff --git a/ui/ui-livedata/api/0.1.0-dev12.txt b/compose/runtime/runtime-livedata/api/0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-livedata/api/0.1.0-dev12.txt
rename to compose/runtime/runtime-livedata/api/0.1.0-dev12.txt
diff --git a/ui/ui-livedata/api/0.1.0-dev14.txt b/compose/runtime/runtime-livedata/api/0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-livedata/api/0.1.0-dev14.txt
rename to compose/runtime/runtime-livedata/api/0.1.0-dev14.txt
diff --git a/ui/ui-livedata/api/0.1.0-dev15.txt b/compose/runtime/runtime-livedata/api/0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-livedata/api/0.1.0-dev15.txt
rename to compose/runtime/runtime-livedata/api/0.1.0-dev15.txt
diff --git a/ui/ui-livedata/api/0.1.0-dev16.txt b/compose/runtime/runtime-livedata/api/0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-livedata/api/0.1.0-dev16.txt
rename to compose/runtime/runtime-livedata/api/0.1.0-dev16.txt
diff --git a/ui/ui-livedata/api/current.txt b/compose/runtime/runtime-livedata/api/current.txt
similarity index 100%
rename from ui/ui-livedata/api/current.txt
rename to compose/runtime/runtime-livedata/api/current.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_0.1.0-dev09.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_0.1.0-dev09.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev09.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_0.1.0-dev10.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_0.1.0-dev10.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev10.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_0.1.0-dev11.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_0.1.0-dev11.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev11.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_0.1.0-dev12.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_0.1.0-dev12.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev12.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_0.1.0-dev14.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_0.1.0-dev14.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev14.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_0.1.0-dev15.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_0.1.0-dev15.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev15.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_0.1.0-dev16.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_0.1.0-dev16.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_0.1.0-dev16.txt
diff --git a/ui/ui-livedata/api/public_plus_experimental_current.txt b/compose/runtime/runtime-livedata/api/public_plus_experimental_current.txt
similarity index 100%
rename from ui/ui-livedata/api/public_plus_experimental_current.txt
rename to compose/runtime/runtime-livedata/api/public_plus_experimental_current.txt
diff --git a/ui/ui-livedata/api/res-0.1.0-dev09.txt b/compose/runtime/runtime-livedata/api/res-0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-livedata/api/res-0.1.0-dev09.txt
rename to compose/runtime/runtime-livedata/api/res-0.1.0-dev09.txt
diff --git a/ui/ui-livedata/api/res-0.1.0-dev10.txt b/compose/runtime/runtime-livedata/api/res-0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-livedata/api/res-0.1.0-dev10.txt
rename to compose/runtime/runtime-livedata/api/res-0.1.0-dev10.txt
diff --git a/ui/ui-livedata/api/res-0.1.0-dev11.txt b/compose/runtime/runtime-livedata/api/res-0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-livedata/api/res-0.1.0-dev11.txt
rename to compose/runtime/runtime-livedata/api/res-0.1.0-dev11.txt
diff --git a/ui/ui-livedata/api/res-0.1.0-dev12.txt b/compose/runtime/runtime-livedata/api/res-0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-livedata/api/res-0.1.0-dev12.txt
rename to compose/runtime/runtime-livedata/api/res-0.1.0-dev12.txt
diff --git a/ui/ui-livedata/api/res-0.1.0-dev14.txt b/compose/runtime/runtime-livedata/api/res-0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-livedata/api/res-0.1.0-dev14.txt
rename to compose/runtime/runtime-livedata/api/res-0.1.0-dev14.txt
diff --git a/ui/ui-livedata/api/res-0.1.0-dev15.txt b/compose/runtime/runtime-livedata/api/res-0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-livedata/api/res-0.1.0-dev15.txt
rename to compose/runtime/runtime-livedata/api/res-0.1.0-dev15.txt
diff --git a/ui/ui-livedata/api/res-0.1.0-dev16.txt b/compose/runtime/runtime-livedata/api/res-0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-livedata/api/res-0.1.0-dev16.txt
rename to compose/runtime/runtime-livedata/api/res-0.1.0-dev16.txt
diff --git a/ui/ui-livedata/api/res-current.txt b/compose/runtime/runtime-livedata/api/res-current.txt
similarity index 100%
rename from ui/ui-livedata/api/res-current.txt
rename to compose/runtime/runtime-livedata/api/res-current.txt
diff --git a/ui/ui-livedata/api/restricted_0.1.0-dev09.txt b/compose/runtime/runtime-livedata/api/restricted_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_0.1.0-dev09.txt
rename to compose/runtime/runtime-livedata/api/restricted_0.1.0-dev09.txt
diff --git a/ui/ui-livedata/api/restricted_0.1.0-dev10.txt b/compose/runtime/runtime-livedata/api/restricted_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_0.1.0-dev10.txt
rename to compose/runtime/runtime-livedata/api/restricted_0.1.0-dev10.txt
diff --git a/ui/ui-livedata/api/restricted_0.1.0-dev11.txt b/compose/runtime/runtime-livedata/api/restricted_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_0.1.0-dev11.txt
rename to compose/runtime/runtime-livedata/api/restricted_0.1.0-dev11.txt
diff --git a/ui/ui-livedata/api/restricted_0.1.0-dev12.txt b/compose/runtime/runtime-livedata/api/restricted_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_0.1.0-dev12.txt
rename to compose/runtime/runtime-livedata/api/restricted_0.1.0-dev12.txt
diff --git a/ui/ui-livedata/api/restricted_0.1.0-dev14.txt b/compose/runtime/runtime-livedata/api/restricted_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_0.1.0-dev14.txt
rename to compose/runtime/runtime-livedata/api/restricted_0.1.0-dev14.txt
diff --git a/ui/ui-livedata/api/restricted_0.1.0-dev15.txt b/compose/runtime/runtime-livedata/api/restricted_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_0.1.0-dev15.txt
rename to compose/runtime/runtime-livedata/api/restricted_0.1.0-dev15.txt
diff --git a/ui/ui-livedata/api/restricted_0.1.0-dev16.txt b/compose/runtime/runtime-livedata/api/restricted_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_0.1.0-dev16.txt
rename to compose/runtime/runtime-livedata/api/restricted_0.1.0-dev16.txt
diff --git a/ui/ui-livedata/api/restricted_current.txt b/compose/runtime/runtime-livedata/api/restricted_current.txt
similarity index 100%
rename from ui/ui-livedata/api/restricted_current.txt
rename to compose/runtime/runtime-livedata/api/restricted_current.txt
diff --git a/ui/ui-livedata/build.gradle b/compose/runtime/runtime-livedata/build.gradle
similarity index 100%
rename from ui/ui-livedata/build.gradle
rename to compose/runtime/runtime-livedata/build.gradle
diff --git a/ui/ui-livedata/samples/build.gradle b/compose/runtime/runtime-livedata/samples/build.gradle
similarity index 100%
rename from ui/ui-livedata/samples/build.gradle
rename to compose/runtime/runtime-livedata/samples/build.gradle
diff --git a/ui/ui-livedata/samples/src/main/AndroidManifest.xml b/compose/runtime/runtime-livedata/samples/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-livedata/samples/src/main/AndroidManifest.xml
rename to compose/runtime/runtime-livedata/samples/src/main/AndroidManifest.xml
diff --git a/ui/ui-livedata/samples/src/main/java/androidx/compose/runtime/livedata/samples/Samples.kt b/compose/runtime/runtime-livedata/samples/src/main/java/androidx/compose/runtime/livedata/samples/Samples.kt
similarity index 99%
rename from ui/ui-livedata/samples/src/main/java/androidx/compose/runtime/livedata/samples/Samples.kt
rename to compose/runtime/runtime-livedata/samples/src/main/java/androidx/compose/runtime/livedata/samples/Samples.kt
index 46fdcee..a2159f7 100644
--- a/ui/ui-livedata/samples/src/main/java/androidx/compose/runtime/livedata/samples/Samples.kt
+++ b/compose/runtime/runtime-livedata/samples/src/main/java/androidx/compose/runtime/livedata/samples/Samples.kt
@@ -17,11 +17,11 @@
package androidx.compose.runtime.livedata.samples
import androidx.annotation.Sampled
+import androidx.compose.foundation.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
-import androidx.lifecycle.LiveData
-import androidx.compose.foundation.Text
import androidx.compose.runtime.livedata.observeAsState
+import androidx.lifecycle.LiveData
@Sampled
@Composable
diff --git a/ui/ui-livedata/src/androidTest/AndroidManifest.xml b/compose/runtime/runtime-livedata/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from ui/ui-livedata/src/androidTest/AndroidManifest.xml
rename to compose/runtime/runtime-livedata/src/androidTest/AndroidManifest.xml
diff --git a/ui/ui-livedata/src/androidTest/java/androidx/compose/runtime/livedata/LiveDataAdapterTest.kt b/compose/runtime/runtime-livedata/src/androidTest/java/androidx/compose/runtime/livedata/LiveDataAdapterTest.kt
similarity index 100%
rename from ui/ui-livedata/src/androidTest/java/androidx/compose/runtime/livedata/LiveDataAdapterTest.kt
rename to compose/runtime/runtime-livedata/src/androidTest/java/androidx/compose/runtime/livedata/LiveDataAdapterTest.kt
diff --git a/ui/ui-livedata/src/main/AndroidManifest.xml b/compose/runtime/runtime-livedata/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-livedata/src/main/AndroidManifest.xml
rename to compose/runtime/runtime-livedata/src/main/AndroidManifest.xml
diff --git a/ui/ui-livedata/src/main/java/androidx/compose/runtime/livedata/LiveDataAdapter.kt b/compose/runtime/runtime-livedata/src/main/java/androidx/compose/runtime/livedata/LiveDataAdapter.kt
similarity index 100%
rename from ui/ui-livedata/src/main/java/androidx/compose/runtime/livedata/LiveDataAdapter.kt
rename to compose/runtime/runtime-livedata/src/main/java/androidx/compose/runtime/livedata/LiveDataAdapter.kt
diff --git a/ui/ui-rxjava2/OWNERS b/compose/runtime/runtime-rxjava2/OWNERS
similarity index 100%
rename from ui/ui-rxjava2/OWNERS
rename to compose/runtime/runtime-rxjava2/OWNERS
diff --git a/ui/ui-rxjava2/api/0.1.0-dev09.txt b/compose/runtime/runtime-rxjava2/api/0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-rxjava2/api/0.1.0-dev09.txt
rename to compose/runtime/runtime-rxjava2/api/0.1.0-dev09.txt
diff --git a/ui/ui-rxjava2/api/0.1.0-dev10.txt b/compose/runtime/runtime-rxjava2/api/0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-rxjava2/api/0.1.0-dev10.txt
rename to compose/runtime/runtime-rxjava2/api/0.1.0-dev10.txt
diff --git a/ui/ui-rxjava2/api/0.1.0-dev11.txt b/compose/runtime/runtime-rxjava2/api/0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-rxjava2/api/0.1.0-dev11.txt
rename to compose/runtime/runtime-rxjava2/api/0.1.0-dev11.txt
diff --git a/ui/ui-rxjava2/api/0.1.0-dev12.txt b/compose/runtime/runtime-rxjava2/api/0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-rxjava2/api/0.1.0-dev12.txt
rename to compose/runtime/runtime-rxjava2/api/0.1.0-dev12.txt
diff --git a/ui/ui-rxjava2/api/0.1.0-dev14.txt b/compose/runtime/runtime-rxjava2/api/0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-rxjava2/api/0.1.0-dev14.txt
rename to compose/runtime/runtime-rxjava2/api/0.1.0-dev14.txt
diff --git a/ui/ui-rxjava2/api/0.1.0-dev15.txt b/compose/runtime/runtime-rxjava2/api/0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-rxjava2/api/0.1.0-dev15.txt
rename to compose/runtime/runtime-rxjava2/api/0.1.0-dev15.txt
diff --git a/ui/ui-rxjava2/api/0.1.0-dev16.txt b/compose/runtime/runtime-rxjava2/api/0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-rxjava2/api/0.1.0-dev16.txt
rename to compose/runtime/runtime-rxjava2/api/0.1.0-dev16.txt
diff --git a/ui/ui-rxjava2/api/current.txt b/compose/runtime/runtime-rxjava2/api/current.txt
similarity index 100%
rename from ui/ui-rxjava2/api/current.txt
rename to compose/runtime/runtime-rxjava2/api/current.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev09.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev09.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev09.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev10.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev10.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev10.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev11.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev11.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev11.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev12.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev12.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev12.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev14.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev14.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev14.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev15.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev15.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev15.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev16.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_0.1.0-dev16.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_0.1.0-dev16.txt
diff --git a/ui/ui-rxjava2/api/public_plus_experimental_current.txt b/compose/runtime/runtime-rxjava2/api/public_plus_experimental_current.txt
similarity index 100%
rename from ui/ui-rxjava2/api/public_plus_experimental_current.txt
rename to compose/runtime/runtime-rxjava2/api/public_plus_experimental_current.txt
diff --git a/ui/ui-rxjava2/api/res-0.1.0-dev09.txt b/compose/runtime/runtime-rxjava2/api/res-0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-0.1.0-dev09.txt
rename to compose/runtime/runtime-rxjava2/api/res-0.1.0-dev09.txt
diff --git a/ui/ui-rxjava2/api/res-0.1.0-dev10.txt b/compose/runtime/runtime-rxjava2/api/res-0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-0.1.0-dev10.txt
rename to compose/runtime/runtime-rxjava2/api/res-0.1.0-dev10.txt
diff --git a/ui/ui-rxjava2/api/res-0.1.0-dev11.txt b/compose/runtime/runtime-rxjava2/api/res-0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-0.1.0-dev11.txt
rename to compose/runtime/runtime-rxjava2/api/res-0.1.0-dev11.txt
diff --git a/ui/ui-rxjava2/api/res-0.1.0-dev12.txt b/compose/runtime/runtime-rxjava2/api/res-0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-0.1.0-dev12.txt
rename to compose/runtime/runtime-rxjava2/api/res-0.1.0-dev12.txt
diff --git a/ui/ui-rxjava2/api/res-0.1.0-dev14.txt b/compose/runtime/runtime-rxjava2/api/res-0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-0.1.0-dev14.txt
rename to compose/runtime/runtime-rxjava2/api/res-0.1.0-dev14.txt
diff --git a/ui/ui-rxjava2/api/res-0.1.0-dev15.txt b/compose/runtime/runtime-rxjava2/api/res-0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-0.1.0-dev15.txt
rename to compose/runtime/runtime-rxjava2/api/res-0.1.0-dev15.txt
diff --git a/ui/ui-rxjava2/api/res-0.1.0-dev16.txt b/compose/runtime/runtime-rxjava2/api/res-0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-0.1.0-dev16.txt
rename to compose/runtime/runtime-rxjava2/api/res-0.1.0-dev16.txt
diff --git a/ui/ui-rxjava2/api/res-current.txt b/compose/runtime/runtime-rxjava2/api/res-current.txt
similarity index 100%
rename from ui/ui-rxjava2/api/res-current.txt
rename to compose/runtime/runtime-rxjava2/api/res-current.txt
diff --git a/ui/ui-rxjava2/api/restricted_0.1.0-dev09.txt b/compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_0.1.0-dev09.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev09.txt
diff --git a/ui/ui-rxjava2/api/restricted_0.1.0-dev10.txt b/compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_0.1.0-dev10.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev10.txt
diff --git a/ui/ui-rxjava2/api/restricted_0.1.0-dev11.txt b/compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_0.1.0-dev11.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev11.txt
diff --git a/ui/ui-rxjava2/api/restricted_0.1.0-dev12.txt b/compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_0.1.0-dev12.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev12.txt
diff --git a/ui/ui-rxjava2/api/restricted_0.1.0-dev14.txt b/compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_0.1.0-dev14.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev14.txt
diff --git a/ui/ui-rxjava2/api/restricted_0.1.0-dev15.txt b/compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_0.1.0-dev15.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev15.txt
diff --git a/ui/ui-rxjava2/api/restricted_0.1.0-dev16.txt b/compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_0.1.0-dev16.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_0.1.0-dev16.txt
diff --git a/ui/ui-rxjava2/api/restricted_current.txt b/compose/runtime/runtime-rxjava2/api/restricted_current.txt
similarity index 100%
rename from ui/ui-rxjava2/api/restricted_current.txt
rename to compose/runtime/runtime-rxjava2/api/restricted_current.txt
diff --git a/ui/ui-rxjava2/build.gradle b/compose/runtime/runtime-rxjava2/build.gradle
similarity index 100%
rename from ui/ui-rxjava2/build.gradle
rename to compose/runtime/runtime-rxjava2/build.gradle
diff --git a/ui/ui-rxjava2/samples/build.gradle b/compose/runtime/runtime-rxjava2/samples/build.gradle
similarity index 100%
rename from ui/ui-rxjava2/samples/build.gradle
rename to compose/runtime/runtime-rxjava2/samples/build.gradle
diff --git a/ui/ui-rxjava2/samples/src/main/AndroidManifest.xml b/compose/runtime/runtime-rxjava2/samples/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-rxjava2/samples/src/main/AndroidManifest.xml
rename to compose/runtime/runtime-rxjava2/samples/src/main/AndroidManifest.xml
diff --git a/ui/ui-rxjava2/samples/src/main/java/androidx/compose/runtime/rxjava2/samples/Samples.kt b/compose/runtime/runtime-rxjava2/samples/src/main/java/androidx/compose/runtime/rxjava2/samples/Samples.kt
similarity index 99%
rename from ui/ui-rxjava2/samples/src/main/java/androidx/compose/runtime/rxjava2/samples/Samples.kt
rename to compose/runtime/runtime-rxjava2/samples/src/main/java/androidx/compose/runtime/rxjava2/samples/Samples.kt
index 277271c..be82303 100644
--- a/ui/ui-rxjava2/samples/src/main/java/androidx/compose/runtime/rxjava2/samples/Samples.kt
+++ b/compose/runtime/runtime-rxjava2/samples/src/main/java/androidx/compose/runtime/rxjava2/samples/Samples.kt
@@ -17,9 +17,9 @@
package androidx.compose.runtime.rxjava2.samples
import androidx.annotation.Sampled
+import androidx.compose.foundation.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
-import androidx.compose.foundation.Text
import androidx.compose.runtime.rxjava2.subscribeAsState
import io.reactivex.Completable
import io.reactivex.Flowable
diff --git a/ui/ui-rxjava2/src/androidTest/AndroidManifest.xml b/compose/runtime/runtime-rxjava2/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from ui/ui-rxjava2/src/androidTest/AndroidManifest.xml
rename to compose/runtime/runtime-rxjava2/src/androidTest/AndroidManifest.xml
diff --git a/ui/ui-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/CompletableAdapterTest.kt b/compose/runtime/runtime-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/CompletableAdapterTest.kt
similarity index 100%
rename from ui/ui-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/CompletableAdapterTest.kt
rename to compose/runtime/runtime-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/CompletableAdapterTest.kt
diff --git a/ui/ui-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/RxJava2AdapterTest.kt b/compose/runtime/runtime-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/RxJava2AdapterTest.kt
similarity index 100%
rename from ui/ui-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/RxJava2AdapterTest.kt
rename to compose/runtime/runtime-rxjava2/src/androidTest/java/androidx/compose/runtime/rxjava2/RxJava2AdapterTest.kt
diff --git a/ui/ui-rxjava2/src/main/AndroidManifest.xml b/compose/runtime/runtime-rxjava2/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-rxjava2/src/main/AndroidManifest.xml
rename to compose/runtime/runtime-rxjava2/src/main/AndroidManifest.xml
diff --git a/ui/ui-rxjava2/src/main/java/androidx/compose/runtime/rxjava2/RxJava2Adapter.kt b/compose/runtime/runtime-rxjava2/src/main/java/androidx/compose/runtime/rxjava2/RxJava2Adapter.kt
similarity index 100%
rename from ui/ui-rxjava2/src/main/java/androidx/compose/runtime/rxjava2/RxJava2Adapter.kt
rename to compose/runtime/runtime-rxjava2/src/main/java/androidx/compose/runtime/rxjava2/RxJava2Adapter.kt
diff --git a/ui/ui-saved-instance-state/OWNERS b/compose/runtime/runtime-saved-instance-state/OWNERS
similarity index 100%
rename from ui/ui-saved-instance-state/OWNERS
rename to compose/runtime/runtime-saved-instance-state/OWNERS
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev07.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev07.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev07.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev08.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev08.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev08.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev09.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev09.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev09.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev10.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev10.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev10.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev11.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev11.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev11.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev12.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev12.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev12.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev14.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev14.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev14.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev15.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev15.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev15.txt
diff --git a/ui/ui-saved-instance-state/api/0.1.0-dev16.txt b/compose/runtime/runtime-saved-instance-state/api/0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/0.1.0-dev16.txt
rename to compose/runtime/runtime-saved-instance-state/api/0.1.0-dev16.txt
diff --git a/ui/ui-saved-instance-state/api/api_lint.ignore b/compose/runtime/runtime-saved-instance-state/api/api_lint.ignore
similarity index 100%
rename from ui/ui-saved-instance-state/api/api_lint.ignore
rename to compose/runtime/runtime-saved-instance-state/api/api_lint.ignore
diff --git a/ui/ui-saved-instance-state/api/current.txt b/compose/runtime/runtime-saved-instance-state/api/current.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/current.txt
rename to compose/runtime/runtime-saved-instance-state/api/current.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev07.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev07.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev07.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev08.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev08.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev08.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev09.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev09.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev09.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev10.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev10.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev10.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev11.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev11.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev11.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev12.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev12.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev12.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev14.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev14.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev14.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev15.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev15.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev15.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev16.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_0.1.0-dev16.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_0.1.0-dev16.txt
diff --git a/ui/ui-saved-instance-state/api/public_plus_experimental_current.txt b/compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_current.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/public_plus_experimental_current.txt
rename to compose/runtime/runtime-saved-instance-state/api/public_plus_experimental_current.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev07.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev07.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev07.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev08.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev08.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev08.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev09.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev09.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev09.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev10.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev10.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev10.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev11.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev11.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev11.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev12.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev12.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev12.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev14.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev14.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev14.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev15.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev15.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev15.txt
diff --git a/ui/ui-saved-instance-state/api/res-0.1.0-dev16.txt b/compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-0.1.0-dev16.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-0.1.0-dev16.txt
diff --git a/ui/ui-saved-instance-state/api/res-current.txt b/compose/runtime/runtime-saved-instance-state/api/res-current.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/res-current.txt
rename to compose/runtime/runtime-saved-instance-state/api/res-current.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev07.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev07.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev07.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev07.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev08.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev08.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev08.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev08.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev09.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev09.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev09.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev09.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev10.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev10.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev10.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev10.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev11.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev11.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev11.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev11.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev12.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev12.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev12.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev12.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev14.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev14.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev14.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev14.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev15.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev15.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev15.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev15.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_0.1.0-dev16.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev16.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_0.1.0-dev16.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_0.1.0-dev16.txt
diff --git a/ui/ui-saved-instance-state/api/restricted_current.txt b/compose/runtime/runtime-saved-instance-state/api/restricted_current.txt
similarity index 100%
rename from ui/ui-saved-instance-state/api/restricted_current.txt
rename to compose/runtime/runtime-saved-instance-state/api/restricted_current.txt
diff --git a/ui/ui-saved-instance-state/build.gradle b/compose/runtime/runtime-saved-instance-state/build.gradle
similarity index 100%
rename from ui/ui-saved-instance-state/build.gradle
rename to compose/runtime/runtime-saved-instance-state/build.gradle
diff --git a/ui/ui-saved-instance-state/samples/build.gradle b/compose/runtime/runtime-saved-instance-state/samples/build.gradle
similarity index 100%
rename from ui/ui-saved-instance-state/samples/build.gradle
rename to compose/runtime/runtime-saved-instance-state/samples/build.gradle
diff --git a/ui/ui-saved-instance-state/samples/src/main/AndroidManifest.xml b/compose/runtime/runtime-saved-instance-state/samples/src/main/AndroidManifest.xml
similarity index 100%
rename from ui/ui-saved-instance-state/samples/src/main/AndroidManifest.xml
rename to compose/runtime/runtime-saved-instance-state/samples/src/main/AndroidManifest.xml
diff --git a/ui/ui-saved-instance-state/samples/src/main/java/androidx/compose/runtime/savedinstancestate/samples/Samples.kt b/compose/runtime/runtime-saved-instance-state/samples/src/main/java/androidx/compose/runtime/savedinstancestate/samples/Samples.kt
similarity index 99%
rename from ui/ui-saved-instance-state/samples/src/main/java/androidx/compose/runtime/savedinstancestate/samples/Samples.kt
rename to compose/runtime/runtime-saved-instance-state/samples/src/main/java/androidx/compose/runtime/savedinstancestate/samples/Samples.kt
index 3894bef..3ee23a6 100644
--- a/ui/ui-saved-instance-state/samples/src/main/java/androidx/compose/runtime/savedinstancestate/samples/Samples.kt
+++ b/compose/runtime/runtime-saved-instance-state/samples/src/main/java/androidx/compose/runtime/savedinstancestate/samples/Samples.kt
@@ -21,12 +21,12 @@
import androidx.annotation.Sampled
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.setValue
import androidx.compose.runtime.savedinstancestate.Saver
import androidx.compose.runtime.savedinstancestate.listSaver
import androidx.compose.runtime.savedinstancestate.mapSaver
import androidx.compose.runtime.savedinstancestate.rememberSavedInstanceState
import androidx.compose.runtime.savedinstancestate.savedInstanceState
+import androidx.compose.runtime.setValue
@Sampled
@Composable
diff --git a/ui/ui-saved-instance-state/src/androidAndroidTest/AndroidManifest.xml b/compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/AndroidManifest.xml
similarity index 100%
rename from ui/ui-saved-instance-state/src/androidAndroidTest/AndroidManifest.xml
rename to compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/AndroidManifest.xml
diff --git a/ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/ActivityRecreationTest.kt b/compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/ActivityRecreationTest.kt
similarity index 99%
rename from ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/ActivityRecreationTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/ActivityRecreationTest.kt
index 53c8e56..6e03fe3 100644
--- a/ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/ActivityRecreationTest.kt
+++ b/compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/ActivityRecreationTest.kt
@@ -24,13 +24,13 @@
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Recomposer
import androidx.compose.runtime.remember
+import androidx.compose.runtime.savedinstancestate.test.R
+import androidx.compose.ui.platform.setContent
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.test.core.app.ActivityScenario
import androidx.test.filters.MediumTest
-import androidx.compose.ui.platform.setContent
-import androidx.compose.runtime.savedinstancestate.test.R
-import androidx.fragment.app.Fragment
-import androidx.fragment.app.FragmentActivity
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/Holder.kt b/compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/Holder.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/Holder.kt
rename to compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/Holder.kt
diff --git a/ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceStateTest.kt b/compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceStateTest.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceStateTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceStateTest.kt
diff --git a/ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RestorationInVariousScenariosTest.kt b/compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RestorationInVariousScenariosTest.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RestorationInVariousScenariosTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/RestorationInVariousScenariosTest.kt
diff --git a/ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceStateTest.kt b/compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceStateTest.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceStateTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/androidAndroidTest/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceStateTest.kt
diff --git a/ui/ui-saved-instance-state/src/androidMain/AndroidManifest.xml b/compose/runtime/runtime-saved-instance-state/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from ui/ui-saved-instance-state/src/androidMain/AndroidManifest.xml
rename to compose/runtime/runtime-saved-instance-state/src/androidMain/AndroidManifest.xml
diff --git a/ui/ui-saved-instance-state/src/androidTest/res/values/ids.xml b/compose/runtime/runtime-saved-instance-state/src/androidTest/res/values/ids.xml
similarity index 100%
rename from ui/ui-saved-instance-state/src/androidTest/res/values/ids.xml
rename to compose/runtime/runtime-saved-instance-state/src/androidTest/res/values/ids.xml
diff --git a/ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/ListSaver.kt b/compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/ListSaver.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/ListSaver.kt
rename to compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/ListSaver.kt
diff --git a/ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/MapSaver.kt b/compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/MapSaver.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/MapSaver.kt
rename to compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/MapSaver.kt
diff --git a/ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceState.kt b/compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceState.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceState.kt
rename to compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/RememberSavedInstanceState.kt
diff --git a/ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceState.kt b/compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceState.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceState.kt
rename to compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/SavedInstanceState.kt
diff --git a/ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/Saver.kt b/compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/Saver.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/Saver.kt
rename to compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/Saver.kt
diff --git a/ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistry.kt b/compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistry.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistry.kt
rename to compose/runtime/runtime-saved-instance-state/src/commonMain/kotlin/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistry.kt
diff --git a/ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/AutoSaverTest.kt b/compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/AutoSaverTest.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/AutoSaverTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/AutoSaverTest.kt
diff --git a/ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/ListSaverTest.kt b/compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/ListSaverTest.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/ListSaverTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/ListSaverTest.kt
diff --git a/ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/MapSaverTest.kt b/compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/MapSaverTest.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/MapSaverTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/MapSaverTest.kt
diff --git a/ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistryTest.kt b/compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistryTest.kt
similarity index 100%
rename from ui/ui-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistryTest.kt
rename to compose/runtime/runtime-saved-instance-state/src/test/java/androidx/compose/runtime/savedinstancestate/UiSavedStateRegistryTest.kt
diff --git a/compose/compose-runtime/api/0.1.0-dev04.txt b/compose/runtime/runtime/api/0.1.0-dev04.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev04.txt
rename to compose/runtime/runtime/api/0.1.0-dev04.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev05.txt b/compose/runtime/runtime/api/0.1.0-dev05.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev05.txt
rename to compose/runtime/runtime/api/0.1.0-dev05.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev06.txt b/compose/runtime/runtime/api/0.1.0-dev06.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev06.txt
rename to compose/runtime/runtime/api/0.1.0-dev06.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev07.txt b/compose/runtime/runtime/api/0.1.0-dev07.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev07.txt
rename to compose/runtime/runtime/api/0.1.0-dev07.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev08.txt b/compose/runtime/runtime/api/0.1.0-dev08.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev08.txt
rename to compose/runtime/runtime/api/0.1.0-dev08.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev09.txt b/compose/runtime/runtime/api/0.1.0-dev09.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev09.txt
rename to compose/runtime/runtime/api/0.1.0-dev09.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev10.txt b/compose/runtime/runtime/api/0.1.0-dev10.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev10.txt
rename to compose/runtime/runtime/api/0.1.0-dev10.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev11.txt b/compose/runtime/runtime/api/0.1.0-dev11.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev11.txt
rename to compose/runtime/runtime/api/0.1.0-dev11.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev12.txt b/compose/runtime/runtime/api/0.1.0-dev12.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev12.txt
rename to compose/runtime/runtime/api/0.1.0-dev12.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev14.txt b/compose/runtime/runtime/api/0.1.0-dev14.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev14.txt
rename to compose/runtime/runtime/api/0.1.0-dev14.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev15.txt b/compose/runtime/runtime/api/0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev15.txt
rename to compose/runtime/runtime/api/0.1.0-dev15.txt
diff --git a/compose/compose-runtime/api/0.1.0-dev16.txt b/compose/runtime/runtime/api/0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-runtime/api/0.1.0-dev16.txt
rename to compose/runtime/runtime/api/0.1.0-dev16.txt
diff --git a/compose/compose-runtime/api/api_lint.ignore b/compose/runtime/runtime/api/api_lint.ignore
similarity index 100%
rename from compose/compose-runtime/api/api_lint.ignore
rename to compose/runtime/runtime/api/api_lint.ignore
diff --git a/compose/compose-runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
similarity index 100%
rename from compose/compose-runtime/api/current.txt
rename to compose/runtime/runtime/api/current.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev04.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev04.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev04.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev04.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev05.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev05.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev05.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev05.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev06.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev06.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev06.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev06.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev07.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev07.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev07.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev07.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev08.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev08.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev08.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev08.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev09.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev09.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev09.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev09.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev10.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev10.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev10.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev10.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev11.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev11.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev11.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev11.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev12.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev12.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev12.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev12.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev14.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev14.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev14.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev14.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev15.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev15.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev15.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev16.txt b/compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_0.1.0-dev16.txt
rename to compose/runtime/runtime/api/public_plus_experimental_0.1.0-dev16.txt
diff --git a/compose/compose-runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
similarity index 100%
rename from compose/compose-runtime/api/public_plus_experimental_current.txt
rename to compose/runtime/runtime/api/public_plus_experimental_current.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev04.txt b/compose/runtime/runtime/api/res-0.1.0-dev04.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev04.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev04.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev05.txt b/compose/runtime/runtime/api/res-0.1.0-dev05.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev05.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev05.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev06.txt b/compose/runtime/runtime/api/res-0.1.0-dev06.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev06.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev06.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev07.txt b/compose/runtime/runtime/api/res-0.1.0-dev07.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev07.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev07.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev08.txt b/compose/runtime/runtime/api/res-0.1.0-dev08.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev08.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev08.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev09.txt b/compose/runtime/runtime/api/res-0.1.0-dev09.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev09.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev09.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev10.txt b/compose/runtime/runtime/api/res-0.1.0-dev10.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev10.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev10.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev11.txt b/compose/runtime/runtime/api/res-0.1.0-dev11.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev11.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev11.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev12.txt b/compose/runtime/runtime/api/res-0.1.0-dev12.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev12.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev12.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev14.txt b/compose/runtime/runtime/api/res-0.1.0-dev14.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev14.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev14.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev15.txt b/compose/runtime/runtime/api/res-0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev15.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev15.txt
diff --git a/compose/compose-runtime/api/res-0.1.0-dev16.txt b/compose/runtime/runtime/api/res-0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-runtime/api/res-0.1.0-dev16.txt
rename to compose/runtime/runtime/api/res-0.1.0-dev16.txt
diff --git a/compose/compose-runtime/api/res-current.txt b/compose/runtime/runtime/api/res-current.txt
similarity index 100%
rename from compose/compose-runtime/api/res-current.txt
rename to compose/runtime/runtime/api/res-current.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev04.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev04.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev04.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev04.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev05.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev05.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev05.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev05.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev06.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev06.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev06.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev06.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev07.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev07.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev07.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev07.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev08.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev08.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev08.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev08.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev09.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev09.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev09.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev09.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev10.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev10.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev10.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev10.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev11.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev11.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev11.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev11.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev12.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev12.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev12.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev12.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev14.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev14.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev14.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev14.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev15.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev15.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev15.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev15.txt
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev16.txt b/compose/runtime/runtime/api/restricted_0.1.0-dev16.txt
similarity index 100%
rename from compose/compose-runtime/api/restricted_0.1.0-dev16.txt
rename to compose/runtime/runtime/api/restricted_0.1.0-dev16.txt
diff --git a/compose/compose-runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
similarity index 99%
rename from compose/compose-runtime/api/restricted_current.txt
rename to compose/runtime/runtime/api/restricted_current.txt
index 4bf593f..bb35e2b 100644
--- a/compose/compose-runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -946,6 +946,7 @@
method public static inline <T extends androidx.compose.runtime.snapshots.StateRecord, R> R! writable(T, androidx.compose.runtime.snapshots.StateObject state, kotlin.jvm.functions.Function1<? super T,? extends R> block);
method @kotlin.PublishedApi internal static <T extends androidx.compose.runtime.snapshots.StateRecord> T writableRecord(T, androidx.compose.runtime.snapshots.StateObject state, androidx.compose.runtime.snapshots.Snapshot snapshot);
field @kotlin.PublishedApi internal static final Object lock;
+ field @kotlin.PublishedApi internal static final androidx.compose.runtime.snapshots.Snapshot snapshotInitializer;
}
@androidx.compose.runtime.Stable public final class SnapshotStateList<T> implements kotlin.jvm.internal.markers.KMutableList java.util.List<T> androidx.compose.runtime.snapshots.StateObject {
diff --git a/compose/compose-runtime/build.gradle b/compose/runtime/runtime/build.gradle
similarity index 100%
rename from compose/compose-runtime/build.gradle
rename to compose/runtime/runtime/build.gradle
diff --git a/compose/compose-runtime/compose-runtime-benchmark/build.gradle b/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/build.gradle
rename to compose/runtime/runtime/compose-runtime-benchmark/build.gradle
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/HotReloadIntegrationTests.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/HotReloadIntegrationTests.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/HotReloadIntegrationTests.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/HotReloadIntegrationTests.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeActivity.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeActivity.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeActivity.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeActivity.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmark.kt
similarity index 99%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmark.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmark.kt
index c119dfe..8d9c251 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmark.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmark.kt
@@ -21,11 +21,11 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.benchmark.realworld4.RealWorld4_FancyWidget_000
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.runtime.benchmark.realworld4.RealWorld4_FancyWidget_000
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmarkBase.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmarkBase.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmarkBase.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/ComposeBenchmarkBase.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DbMonsterBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DbMonsterBenchmark.kt
similarity index 99%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DbMonsterBenchmark.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DbMonsterBenchmark.kt
index 4feea7a..f9029f1 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DbMonsterBenchmark.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DbMonsterBenchmark.kt
@@ -16,14 +16,14 @@
package androidx.compose.runtime.benchmark
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.runtime.benchmark.dbmonster.DatabaseList
import androidx.compose.runtime.benchmark.dbmonster.DatabaseRow
+import androidx.compose.ui.Modifier
import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
-import androidx.compose.ui.Modifier
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxHeight
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DeepTreeBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DeepTreeBenchmark.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DeepTreeBenchmark.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/DeepTreeBenchmark.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SiblingBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SiblingBenchmark.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SiblingBenchmark.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SiblingBenchmark.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/collection/MutableVectorBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/collection/MutableVectorBenchmark.kt
similarity index 99%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/collection/MutableVectorBenchmark.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/collection/MutableVectorBenchmark.kt
index f252e03..7059121 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/collection/MutableVectorBenchmark.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/collection/MutableVectorBenchmark.kt
@@ -21,11 +21,11 @@
import androidx.compose.runtime.collection.ExperimentalCollectionApi
import androidx.compose.runtime.collection.MutableVector
import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.LargeTest
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastSumBy
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/dbmonster/DbMonster.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/dbmonster/DbMonster.kt
similarity index 99%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/dbmonster/DbMonster.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/dbmonster/DbMonster.kt
index 5b2df5a5..c993323 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/dbmonster/DbMonster.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/dbmonster/DbMonster.kt
@@ -16,16 +16,16 @@
package androidx.compose.runtime.benchmark.dbmonster
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
import androidx.compose.foundation.Text
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
import kotlin.random.Random
private fun randomQuery(random: Random): String = random.nextDouble().let {
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/deeptree/DeepTree.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/deeptree/DeepTree.kt
similarity index 99%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/deeptree/DeepTree.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/deeptree/DeepTree.kt
index 31c3719..1f941ef 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/deeptree/DeepTree.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/deeptree/DeepTree.kt
@@ -16,16 +16,16 @@
package androidx.compose.runtime.benchmark.deeptree
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
import androidx.compose.foundation.Box
import androidx.compose.foundation.background
-import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
val blueBackground = Modifier.background(color = Color.Blue)
val magentaBackground = Modifier.background(color = Color.Magenta)
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/README.md b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/README.md
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/README.md
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/README.md
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_DataModels.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_DataModels.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_DataModels.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_DataModels.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_UnmemoizablePojos.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_UnmemoizablePojos.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_UnmemoizablePojos.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_UnmemoizablePojos.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Utilities.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Utilities.kt
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Utilities.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Utilities.kt
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Widgets.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Widgets.kt
similarity index 99%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Widgets.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Widgets.kt
index 9412ad6..2513649 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Widgets.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/realworld4/RealWorld4_Widgets.kt
@@ -24,17 +24,17 @@
* large scale (eg. gmail-sized application).
*/
+import androidx.compose.foundation.Box
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.WithConstraints
import androidx.compose.ui.graphics.Color
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.Box
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.ui.unit.dp
import kotlin.reflect.KCallable
import kotlin.reflect.full.memberProperties
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/siblings/SiblingManagement.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/siblings/SiblingManagement.kt
similarity index 99%
rename from compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/siblings/SiblingManagement.kt
rename to compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/siblings/SiblingManagement.kt
index 8acc8b5..8b69b025 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/siblings/SiblingManagement.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/siblings/SiblingManagement.kt
@@ -16,18 +16,18 @@
package androidx.compose.runtime.benchmark.siblings
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.key
-import androidx.compose.ui.Modifier
import androidx.compose.foundation.Box
import androidx.compose.foundation.Text
import androidx.compose.foundation.background
-import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.key
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import kotlin.random.Random
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/main/AndroidManifest.xml b/compose/runtime/runtime/compose-runtime-benchmark/src/main/AndroidManifest.xml
similarity index 100%
rename from compose/compose-runtime/compose-runtime-benchmark/src/main/AndroidManifest.xml
rename to compose/runtime/runtime/compose-runtime-benchmark/src/main/AndroidManifest.xml
diff --git a/compose/compose-runtime/lint-baseline.xml b/compose/runtime/runtime/lint-baseline.xml
similarity index 100%
rename from compose/compose-runtime/lint-baseline.xml
rename to compose/runtime/runtime/lint-baseline.xml
diff --git a/compose/compose-runtime/samples/build.gradle b/compose/runtime/runtime/samples/build.gradle
similarity index 100%
rename from compose/compose-runtime/samples/build.gradle
rename to compose/runtime/runtime/samples/build.gradle
diff --git a/compose/compose-runtime/samples/src/main/AndroidManifest.xml b/compose/runtime/runtime/samples/src/main/AndroidManifest.xml
similarity index 100%
rename from compose/compose-runtime/samples/src/main/AndroidManifest.xml
rename to compose/runtime/runtime/samples/src/main/AndroidManifest.xml
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/AmbientSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/AmbientSamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/AmbientSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/AmbientSamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/CustomTreeCompositionSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CustomTreeCompositionSamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/CustomTreeCompositionSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/CustomTreeCompositionSamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/EffectSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/EffectSamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/EffectSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/EffectSamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/FlowAdapterSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/FlowAdapterSamples.kt
similarity index 99%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/FlowAdapterSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/FlowAdapterSamples.kt
index bc42ebd..64a0a52 100644
--- a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/FlowAdapterSamples.kt
+++ b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/FlowAdapterSamples.kt
@@ -17,10 +17,10 @@
package androidx.compose.runtime.samples
import androidx.annotation.Sampled
+import androidx.compose.foundation.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
-import androidx.compose.foundation.Text
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/ImmutableSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/ImmutableSamples.kt
similarity index 99%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/ImmutableSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/ImmutableSamples.kt
index 6293e58..2d91ae0 100644
--- a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/ImmutableSamples.kt
+++ b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/ImmutableSamples.kt
@@ -17,11 +17,11 @@
package androidx.compose.runtime.samples
import androidx.annotation.Sampled
+import androidx.compose.foundation.Text
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
-import androidx.compose.foundation.Text
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Column
@Sampled
@Composable
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/KeySamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/KeySamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/KeySamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/KeySamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/ModelSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/ModelSamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/ModelSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/ModelSamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateListSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateListSamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateListSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateListSamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateMapSample.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateMapSample.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateMapSample.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/MutableStateMapSample.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/SharedSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SharedSamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/SharedSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SharedSamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/SlotTableSamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SlotTableSamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/SlotTableSamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SlotTableSamples.kt
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotMutationPolicySamples.kt b/compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotMutationPolicySamples.kt
similarity index 100%
rename from compose/compose-runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotMutationPolicySamples.kt
rename to compose/runtime/runtime/samples/src/main/java/androidx/compose/runtime/samples/SnapshotMutationPolicySamples.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/AndroidManifest.xml b/compose/runtime/runtime/src/androidAndroidTest/AndroidManifest.xml
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/AndroidManifest.xml
rename to compose/runtime/runtime/src/androidAndroidTest/AndroidManifest.xml
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
similarity index 99%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
index 67114f3..5d51473 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
@@ -18,12 +18,12 @@
package androidx.compose.runtime
import android.widget.TextView
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
import androidx.compose.ui.node.ExperimentalLayoutNodeApi
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.platform.subcomposeInto
import androidx.compose.ui.viewinterop.emitView
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
import org.junit.After
import org.junit.Rule
import org.junit.Test
diff --git a/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AndroidSnapshotTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AndroidSnapshotTests.kt
new file mode 100644
index 0000000..7a3b9ac
--- /dev/null
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AndroidSnapshotTests.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 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.runtime
+
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class AndroidSnapshotTests : BaseComposeTest() {
+ @get:Rule
+ override val activityRule = makeTestActivityRule()
+
+ @OptIn(ExperimentalComposeApi::class)
+ @Test // regression test for b/163903673
+ fun testCommittingInABackgroundThread() {
+ val states = Array(10000) { mutableStateOf(0) }
+ var stop = false
+ object : Thread() {
+ override fun run() {
+ while (!stop) {
+ for (state in states) {
+ state.value = state.value + 1
+ }
+ sleep(1)
+ }
+ }
+ }.start()
+ try {
+ val unregister = Snapshot.registerApplyObserver { changed, _ ->
+ // Try to catch a concurrent modification exception
+ val iterator = changed.iterator()
+ while (iterator.hasNext()) {
+ iterator.next()
+ }
+ }
+ try {
+ repeat(1000) {
+ activityRule.activity.uiThread {
+ Snapshot.sendApplyNotifications()
+ }
+ }
+ } finally {
+ unregister()
+ }
+ } finally {
+ stop = true
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
similarity index 99%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
index 8f2bd65..cdacd935 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
@@ -17,20 +17,20 @@
@file:Suppress("PLUGIN_ERROR")
package androidx.compose.runtime
-import android.os.Bundle
-import android.widget.LinearLayout
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertTrue
import android.app.Activity
+import android.os.Bundle
import android.os.Looper
import android.view.ViewGroup
+import android.widget.LinearLayout
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.ui.node.ExperimentalLayoutNodeApi
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.platform.ContextAmbient
import androidx.compose.ui.platform.setViewContent
import androidx.compose.ui.platform.subcomposeInto
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertTrue
class TestActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeIntoTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeIntoTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeIntoTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeIntoTests.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeModelTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeModelTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeModelTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/ComposeModelTests.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/CompoundHashKeyTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/CompoundHashKeyTests.kt
similarity index 99%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/CompoundHashKeyTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/CompoundHashKeyTests.kt
index b8c38ca..3633e3b 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/CompoundHashKeyTests.kt
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/CompoundHashKeyTests.kt
@@ -20,8 +20,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import org.junit.Rule
-import org.junit.runner.RunWith
import org.junit.Test
+import org.junit.runner.RunWith
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/DisposeTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/DisposeTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/DisposeTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/DisposeTests.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EffectsTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EffectsTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EffectsTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EffectsTests.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EmittableComposer.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EmittableComposer.kt
similarity index 99%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EmittableComposer.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EmittableComposer.kt
index fa7d7f5..6d646c7 100644
--- a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EmittableComposer.kt
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/EmittableComposer.kt
@@ -16,9 +16,9 @@
package androidx.compose.runtime
import android.view.View
-import android.widget.TextView
import android.widget.Button
import android.widget.LinearLayout
+import android.widget.TextView
import androidx.compose.ui.viewinterop.emitView
@Composable
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/FlowAdapterTest.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/FlowAdapterTest.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/FlowAdapterTest.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/FlowAdapterTest.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/NewCodeGenTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/NewCodeGenTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/NewCodeGenTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/NewCodeGenTests.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RecomposerTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RecomposerTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RecomposerTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RecomposerTests.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RestartTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RestartTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RestartTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/RestartTests.kt
diff --git a/compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
similarity index 100%
rename from compose/compose-runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
rename to compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
diff --git a/compose/compose-runtime/src/androidMain/AndroidManifest.xml b/compose/runtime/runtime/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from compose/compose-runtime/src/androidMain/AndroidManifest.xml
rename to compose/runtime/runtime/src/androidMain/AndroidManifest.xml
diff --git a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt
similarity index 100%
rename from compose/compose-runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt
rename to compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt
diff --git a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt
similarity index 100%
rename from compose/compose-runtime/src/androidMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt
rename to compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Ambient.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Ambient.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Ambient.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Ambient.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Applier.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/BitwiseOperators.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BitwiseOperators.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/BitwiseOperators.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BitwiseOperators.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Composable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composable.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Composable.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composable.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposableContract.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposableContract.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposableContract.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposableContract.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Compose.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Compose.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Compose.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Compose.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeCompilerApi.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeCompilerApi.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeCompilerApi.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeCompilerApi.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ComposeVersion.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionFrameClock.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionFrameClock.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionFrameClock.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionFrameClock.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLifecycleObserver.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLifecycleObserver.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLifecycleObserver.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLifecycleObserver.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Effects.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/EmbeddingContext.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/EmbeddingContext.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/EmbeddingContext.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/EmbeddingContext.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Emit.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Emit.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Emit.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Emit.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ExperimentalComposeApi.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ExperimentalComposeApi.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ExperimentalComposeApi.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ExperimentalComposeApi.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/FlowAdapter.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/FlowAdapter.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/FlowAdapter.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/FlowAdapter.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/FrameManager.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/FrameManager.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/FrameManager.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/FrameManager.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Immutable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Immutable.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Immutable.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Immutable.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/InternalComposeApi.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/InternalComposeApi.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/InternalComposeApi.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/InternalComposeApi.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/JoinedKey.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/JoinedKey.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/JoinedKey.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/JoinedKey.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Key.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Key.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Key.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Key.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/KeySourceInfo.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Latch.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Latch.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Latch.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Latch.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/MutableState.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MutableState.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/MutableState.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MutableState.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/NoLiveLiterals.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/NoLiveLiterals.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/NoLiveLiterals.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/NoLiveLiterals.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ObserverMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ObserverMap.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ObserverMap.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ObserverMap.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/OpaqueKey.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/OpaqueKey.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/OpaqueKey.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/OpaqueKey.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Remember.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Remember.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Remember.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Remember.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SlotTable.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Stable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stable.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Stable.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stable.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/StableMarker.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/StableMarker.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/StableMarker.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/StableMarker.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Stack.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Trace.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Trace.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/Trace.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Trace.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/UnionType.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/UnionType.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/UnionType.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/UnionType.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ValueHolders.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/ExperimentalCollectionApi.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/ExperimentalCollectionApi.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/ExperimentalCollectionApi.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/ExperimentalCollectionApi.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/collection/MutableVector.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameContainers.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameContainers.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameContainers.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameContainers.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameIdSet.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameIdSet.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameIdSet.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/FrameIdSet.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/Frames.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/Frames.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/Frames.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/frames/Frames.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/ComposableLambda.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/LiveLiteral.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/LiveLiteral.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/LiveLiteral.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/internal/LiveLiteral.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
similarity index 98%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index 0785ddc..0655c7a 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -1371,6 +1371,15 @@
openSnapshots = openSnapshots.set(it.id)
}
+// A value to use to initialize the snapshot local variable of writable below. The value of this
+// doesn't matter as it is just used to initialize the local that is immediately overwritten by
+// Snapshot.current. This is done to avoid a compiler error complaining that the var has not been
+// initialized. This can be removed once contracts are out of experimental; then we can mark sync
+// with the correct contracts so the compiler would be able to figure out that the variable is
+// initialized.
+@PublishedApi
+internal val snapshotInitializer: Snapshot = currentGlobalSnapshot
+
private fun <T> takeNewGlobalSnapshot(
previousGlobalSnapshot: Snapshot,
block: (invalid: SnapshotIdSet) -> T
@@ -1602,8 +1611,15 @@
* called for the first state record in a state object. A record is writable if it was created in
* the current mutable snapshot.
*/
-inline fun <T : StateRecord, R> T.writable(state: StateObject, block: T.() -> R): R =
- this.writable(state, Snapshot.current, block)
+inline fun <T : StateRecord, R> T.writable(state: StateObject, block: T.() -> R): R {
+ var snapshot: Snapshot = snapshotInitializer
+ return sync {
+ snapshot = Snapshot.current
+ this.writableRecord(state, snapshot).block()
+ }.also {
+ notifyWrite(snapshot, state)
+ }
+}
/**
* Produce a set of optimistic merges of the state records, this is performed outside the
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSet.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateList.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMap.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt
similarity index 100%
rename from compose/compose-runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/tooling/InspectionTables.kt
diff --git a/compose/compose-runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt b/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
similarity index 99%
rename from compose/compose-runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
rename to compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
index 1ae7a9b..8806b4b 100644
--- a/compose/compose-runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
+++ b/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
@@ -16,9 +16,9 @@
package androidx.compose.runtime
+import androidx.compose.runtime.dispatch.DesktopUiDispatcher
import javax.swing.SwingUtilities
import kotlin.coroutines.CoroutineContext
-import androidx.compose.runtime.dispatch.DesktopUiDispatcher
// API to allow override embedding context creation mechanism for tests.
var EmbeddingContextFactory: (() -> EmbeddingContext)? = null
diff --git a/compose/compose-runtime/src/jvmMain/kotlin/androidx/compose/runtime/ActualJvm.kt b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/ActualJvm.kt
similarity index 99%
rename from compose/compose-runtime/src/jvmMain/kotlin/androidx/compose/runtime/ActualJvm.kt
rename to compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/ActualJvm.kt
index 88a0946c..86f1cba 100644
--- a/compose/compose-runtime/src/jvmMain/kotlin/androidx/compose/runtime/ActualJvm.kt
+++ b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/ActualJvm.kt
@@ -16,9 +16,9 @@
package androidx.compose.runtime
+import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.PersistentMap
import kotlinx.collections.immutable.persistentHashMapOf
-import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
internal actual typealias BitSet = java.util.BitSet
diff --git a/compose/compose-runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.kt b/compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.kt
similarity index 100%
rename from compose/compose-runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.kt
rename to compose/runtime/runtime/src/jvmMain/kotlin/androidx/compose/runtime/internal/ComposableLambdaN.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/CompositionTests.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/LatchTest.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/LatchTest.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/LatchTest.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/LatchTest.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/ObserverMapTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/ObserverMapTests.kt
similarity index 99%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/ObserverMapTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/ObserverMapTests.kt
index fdbf94f..8828ff6 100644
--- a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/ObserverMapTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/ObserverMapTests.kt
@@ -16,9 +16,9 @@
package androidx.compose.runtime
-import kotlin.test.assertEquals
import kotlin.test.BeforeTest
import kotlin.test.Test
+import kotlin.test.assertEquals
class ObserverMapTests {
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/SlotTableTests.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/collection/MutableVectorTest.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/collection/MutableVectorTest.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/collection/MutableVectorTest.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/collection/MutableVectorTest.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeContact.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeContact.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeContact.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeContact.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposePoints.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposePoints.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposePoints.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposePoints.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeReport.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeReport.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeReport.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ComposeReport.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Contact.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Contact.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Contact.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Contact.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ContactModel.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ContactModel.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ContactModel.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ContactModel.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/MockViewValidator.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/MockViewValidator.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/MockViewValidator.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/MockViewValidator.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Point.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Point.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Point.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Point.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Report.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Report.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Report.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Report.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/View.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/View.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/View.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/View.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ViewApplier.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ViewApplier.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/ViewApplier.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/ViewApplier.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Views.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Views.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/mock/Views.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/Views.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSetTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSetTests.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSetTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotIdSetTests.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
similarity index 99%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
index 52e4a71..8f0e0f1 100644
--- a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateListTests.kt
@@ -16,13 +16,12 @@
package androidx.compose.runtime.snapshots
-import java.lang.IllegalStateException
+import androidx.compose.runtime.ExperimentalComposeApi
+import androidx.compose.runtime.mutableStateListOf
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
-import androidx.compose.runtime.ExperimentalComposeApi
-import androidx.compose.runtime.mutableStateListOf
class SnapshotStateListTests {
@Test
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateMapTests.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserverTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserverTests.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserverTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserverTests.kt
diff --git a/compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt
similarity index 100%
rename from compose/compose-runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/snapshots/SnapshotTests.kt
diff --git a/datastore/datastore-core/api/current.txt b/datastore/datastore-core/api/current.txt
index c29edba..80f8b50 100644
--- a/datastore/datastore-core/api/current.txt
+++ b/datastore/datastore-core/api/current.txt
@@ -23,8 +23,8 @@
public final class DataStoreFactory {
ctor public DataStoreFactory();
- method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<T>>> migrationProducers = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<T>>> migrationProducers = listOf());
+ method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
+ method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
}
@@ -47,13 +47,17 @@
package androidx.datastore.migrations {
- public interface MigrationFromSharedPreferences<T> {
- method public suspend Object? migrate(androidx.datastore.migrations.SharedPreferencesView prefs, T? currentData, kotlin.coroutines.Continuation<? super T> p);
- method public default suspend Object? shouldMigrate(T? currentData, kotlin.coroutines.Continuation<? super java.lang.Boolean> p);
+ public final class SharedPreferencesMigration<T> implements androidx.datastore.DataMigration<T> {
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, boolean deleteEmptyPreferences, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super java.lang.Boolean>,?> shouldRunMigration, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, boolean deleteEmptyPreferences, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ method @kotlin.jvm.Throws(exceptionClasses=IOException::class) public suspend Object? cleanUp(kotlin.coroutines.Continuation<? super kotlin.Unit> p) throws java.io.IOException;
+ method public suspend Object? migrate(T? currentData, kotlin.coroutines.Continuation<? super T> p);
+ method public suspend Object? shouldMigrate(T? currentData, kotlin.coroutines.Continuation<? super java.lang.Boolean> p);
}
- public final class SharedPreferencesMigration {
- method public static <T> kotlin.jvm.functions.Function0<androidx.datastore.DataMigration<T>> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, androidx.datastore.migrations.MigrationFromSharedPreferences<T> migration, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ public final class SharedPreferencesMigrationKt {
}
public final class SharedPreferencesView {
diff --git a/datastore/datastore-core/api/public_plus_experimental_current.txt b/datastore/datastore-core/api/public_plus_experimental_current.txt
index c29edba..80f8b50 100644
--- a/datastore/datastore-core/api/public_plus_experimental_current.txt
+++ b/datastore/datastore-core/api/public_plus_experimental_current.txt
@@ -23,8 +23,8 @@
public final class DataStoreFactory {
ctor public DataStoreFactory();
- method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<T>>> migrationProducers = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<T>>> migrationProducers = listOf());
+ method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
+ method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
}
@@ -47,13 +47,17 @@
package androidx.datastore.migrations {
- public interface MigrationFromSharedPreferences<T> {
- method public suspend Object? migrate(androidx.datastore.migrations.SharedPreferencesView prefs, T? currentData, kotlin.coroutines.Continuation<? super T> p);
- method public default suspend Object? shouldMigrate(T? currentData, kotlin.coroutines.Continuation<? super java.lang.Boolean> p);
+ public final class SharedPreferencesMigration<T> implements androidx.datastore.DataMigration<T> {
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, boolean deleteEmptyPreferences, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super java.lang.Boolean>,?> shouldRunMigration, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, boolean deleteEmptyPreferences, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ method @kotlin.jvm.Throws(exceptionClasses=IOException::class) public suspend Object? cleanUp(kotlin.coroutines.Continuation<? super kotlin.Unit> p) throws java.io.IOException;
+ method public suspend Object? migrate(T? currentData, kotlin.coroutines.Continuation<? super T> p);
+ method public suspend Object? shouldMigrate(T? currentData, kotlin.coroutines.Continuation<? super java.lang.Boolean> p);
}
- public final class SharedPreferencesMigration {
- method public static <T> kotlin.jvm.functions.Function0<androidx.datastore.DataMigration<T>> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, androidx.datastore.migrations.MigrationFromSharedPreferences<T> migration, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ public final class SharedPreferencesMigrationKt {
}
public final class SharedPreferencesView {
diff --git a/datastore/datastore-core/api/restricted_current.txt b/datastore/datastore-core/api/restricted_current.txt
index c29edba..80f8b50 100644
--- a/datastore/datastore-core/api/restricted_current.txt
+++ b/datastore/datastore-core/api/restricted_current.txt
@@ -23,8 +23,8 @@
public final class DataStoreFactory {
ctor public DataStoreFactory();
- method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<T>>> migrationProducers = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<T>>> migrationProducers = listOf());
+ method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
+ method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<T>> migrations = listOf());
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer, androidx.datastore.handlers.ReplaceFileCorruptionHandler<T>? corruptionHandler = null);
method public <T> androidx.datastore.DataStore<T> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.Serializer<T> serializer);
}
@@ -47,13 +47,17 @@
package androidx.datastore.migrations {
- public interface MigrationFromSharedPreferences<T> {
- method public suspend Object? migrate(androidx.datastore.migrations.SharedPreferencesView prefs, T? currentData, kotlin.coroutines.Continuation<? super T> p);
- method public default suspend Object? shouldMigrate(T? currentData, kotlin.coroutines.Continuation<? super java.lang.Boolean> p);
+ public final class SharedPreferencesMigration<T> implements androidx.datastore.DataMigration<T> {
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, boolean deleteEmptyPreferences, kotlin.jvm.functions.Function2<? super T,? super kotlin.coroutines.Continuation<? super java.lang.Boolean>,?> shouldRunMigration, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, boolean deleteEmptyPreferences, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ ctor public SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, kotlin.jvm.functions.Function3<? super androidx.datastore.migrations.SharedPreferencesView,? super T,? super kotlin.coroutines.Continuation<? super T>,?> migrate);
+ method @kotlin.jvm.Throws(exceptionClasses=IOException::class) public suspend Object? cleanUp(kotlin.coroutines.Continuation<? super kotlin.Unit> p) throws java.io.IOException;
+ method public suspend Object? migrate(T? currentData, kotlin.coroutines.Continuation<? super T> p);
+ method public suspend Object? shouldMigrate(T? currentData, kotlin.coroutines.Continuation<? super java.lang.Boolean> p);
}
- public final class SharedPreferencesMigration {
- method public static <T> kotlin.jvm.functions.Function0<androidx.datastore.DataMigration<T>> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, androidx.datastore.migrations.MigrationFromSharedPreferences<T> migration, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ public final class SharedPreferencesMigrationKt {
}
public final class SharedPreferencesView {
diff --git a/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt b/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt
index b0edfb0..bb90413 100644
--- a/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt
+++ b/datastore/datastore-core/src/androidTest/java/migrations/SharedPreferencesMigrationTest.kt
@@ -58,20 +58,12 @@
@Test
fun testShouldMigrateSkipsMigration() = runBlockingTest {
- val migration = object : MigrationFromSharedPreferences<Byte> {
- override suspend fun shouldMigrate(currentData: Byte) = false
-
- override suspend fun migrate(
- prefs: SharedPreferencesView,
- currentData: Byte
- ) = throw IllegalStateException("Migration is skipped.")
- }
-
- val sharedPrefsMigration = SharedPreferencesMigration(
+ val sharedPrefsMigration = SharedPreferencesMigration<Byte>(
context = context,
sharedPreferencesName = sharedPrefsName,
- migration = migration
- )
+ shouldRunMigration = { false }) { _: SharedPreferencesView, _: Byte ->
+ throw IllegalStateException("Migration should've been skipped.")
+ }
val dataStore = getDataStoreWithMigrations(listOf(sharedPrefsMigration))
@@ -91,28 +83,17 @@
.putInt(notMigratedKey, 123).commit()
).isTrue()
- val migration = object : MigrationFromSharedPreferences<Byte> {
- override suspend fun shouldMigrate(currentData: Byte) = true
-
- override suspend fun migrate(
- prefs: SharedPreferencesView,
- currentData: Byte
- ): Byte {
- assertThat(prefs.getInt(includedKey, -1)).isEqualTo(includedVal)
- assertThrows<IllegalStateException> { prefs.getInt(notMigratedKey, -1) }
-
- assertThat(prefs.getAll()).isEqualTo(mapOf(includedKey to includedVal))
-
- return 99.toByte()
- }
- }
-
val sharedPrefsMigration = SharedPreferencesMigration(
context = context,
sharedPreferencesName = sharedPrefsName,
- migration = migration,
keysToMigrate = setOf(includedKey)
- )
+ ) { prefs: SharedPreferencesView, _: Byte ->
+ assertThat(prefs.getInt(includedKey, -1)).isEqualTo(includedVal)
+ assertThrows<IllegalStateException> { prefs.getInt(notMigratedKey, -1) }
+ assertThat(prefs.getAll()).isEqualTo(mapOf(includedKey to includedVal))
+
+ 99.toByte()
+ }
val dataStore = getDataStoreWithMigrations(listOf(sharedPrefsMigration))
@@ -135,27 +116,17 @@
.commit()
).isTrue()
- val migration = object : MigrationFromSharedPreferences<Byte> {
- override suspend fun shouldMigrate(currentData: Byte) = true
-
- override suspend fun migrate(
- prefs: SharedPreferencesView,
- currentData: Byte
- ): Byte {
- assertThat(prefs.getInt(key1, -1)).isEqualTo(val1)
- assertThat(prefs.getInt(key2, -1)).isEqualTo(val2)
-
- assertThat(prefs.getAll()).isEqualTo(mapOf(key1 to val1, key2 to val2))
-
- return 99.toByte()
- }
- }
-
val sharedPrefsMigration = SharedPreferencesMigration(
context = context,
- sharedPreferencesName = sharedPrefsName,
- migration = migration
- )
+ sharedPreferencesName = sharedPrefsName
+ ) { prefs: SharedPreferencesView, _: Byte ->
+ assertThat(prefs.getInt(key1, -1)).isEqualTo(val1)
+ assertThat(prefs.getInt(key2, -1)).isEqualTo(val2)
+
+ assertThat(prefs.getAll()).isEqualTo(mapOf(key1 to val1, key2 to val2))
+
+ 99.toByte()
+ }
val dataStore = getDataStoreWithMigrations(listOf(sharedPrefsMigration))
@@ -165,12 +136,12 @@
}
private fun getDataStoreWithMigrations(
- migrationProducers: List<() -> DataMigration<Byte>>
+ migrations: List<DataMigration<Byte>>
): DataStore<Byte> {
return DataStoreFactory().create(
produceFile = { datastoreFile },
serializer = TestingSerializer(),
- migrationProducers = migrationProducers,
+ migrations = migrations,
scope = TestCoroutineScope()
)
}
diff --git a/datastore/datastore-core/src/main/java/androidx/datastore/DataMigration.kt b/datastore/datastore-core/src/main/java/androidx/datastore/DataMigration.kt
index 892f4cc..aca7f29 100644
--- a/datastore/datastore-core/src/main/java/androidx/datastore/DataMigration.kt
+++ b/datastore/datastore-core/src/main/java/androidx/datastore/DataMigration.kt
@@ -17,15 +17,23 @@
package androidx.datastore
/**
- * Interface for migrations to DataStore. If you're migrating from SharedPreferences see
- * [SharedPreferencesMigration].
+ * Interface for migrations to DataStore. Methods on this migration ([shouldMigrate], [migrate]
+ * and [cleanUp]) may be called multiple times, so their implementations must be idempotent.
+ * These methods may be called multiple times if DataStore encounters issues when writing the
+ * newly migrated data to disk or if any migration installed in the same DataStore throws an
+ * Exception.
+ *
+ * If you're migrating from SharedPreferences see [SharedPreferencesMigration].
*/
interface DataMigration<T> {
/**
* Return whether this migration needs to be performed. If this returns false, no migration or
* cleanup will occur. Apps should do the cheapest possible check to determine if this migration
- * should run, since this will be called every time the DataStore is initialized.
+ * should run, since this will be called every time the DataStore is initialized. This method
+ * may be run multiple times when any failure is encountered.
+ *
+ * Note that this will always be called before each call to [migrate].
*
* @param currentData the current data (which might already populated from previous runs of this
* or other migrations)
@@ -37,7 +45,9 @@
* multiple times. If migrate fails, DataStore will not commit any data to disk, cleanUp will
* not be called, and the exception will be propagated back to the DataStore call that
* triggered the migration. Future calls to DataStore will result in DataMigrations being
- * attempted again.
+ * attempted again. This method may be run multiple times when any failure is encountered.
+ *
+ * Note that this will always be called before a call to [cleanUp].
*
* @param currentData the current data (it might be populated from other migrations or from
* manual changes before this migration was added to the app)
@@ -49,7 +59,8 @@
* Clean up any old state/data that was migrated into the DataStore. This will not be called
* if the migration fails. If cleanUp throws an exception, the exception will be propagated
* back to the DataStore call that triggered the migration and future calls to DataStore will
- * result in DataMigrations being attempted again.
+ * result in DataMigrations being attempted again. This method may be run multiple times when
+ * any failure is encountered.
*/
suspend fun cleanUp()
}
\ No newline at end of file
diff --git a/datastore/datastore-core/src/main/java/androidx/datastore/DataMigrationInitializer.kt b/datastore/datastore-core/src/main/java/androidx/datastore/DataMigrationInitializer.kt
index 42ea187..e5dea0f 100644
--- a/datastore/datastore-core/src/main/java/androidx/datastore/DataMigrationInitializer.kt
+++ b/datastore/datastore-core/src/main/java/androidx/datastore/DataMigrationInitializer.kt
@@ -24,18 +24,13 @@
/**
* Creates an initializer from DataMigrations for use with DataStore.
*
- * @param migrationTaskFactories A list of functions that return migrations that will be
- * included in the initializer. If the DataMigration contains any state, the function
- * should return a new migration each time it is called.
+ * @param migrations A list of migrations that will be included in the initializer.
* @return The initializer which includes the data migrations returned from the factory
* functions.
*/
- fun <T> getInitializer(migrationTaskFactories: List<() -> DataMigration<T>>):
- suspend (api: InitializerApi<T>) -> Unit {
- return { api ->
- val migrations = migrationTaskFactories.map { it() }
- runMigrations(migrations, api)
- }
+ fun <T> getInitializer(migrations: List<DataMigration<T>>):
+ suspend (api: InitializerApi<T>) -> Unit = { api ->
+ runMigrations(migrations, api)
}
private suspend fun <T> runMigrations(
diff --git a/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt b/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
index 5e7745f..969495e 100644
--- a/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
+++ b/datastore/datastore-core/src/main/java/androidx/datastore/DataStoreFactory.kt
@@ -44,23 +44,23 @@
* @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a
* [CorruptionException] when attempting to read data. CorruptionExceptions are thrown by
* serializers when data can not be de-serialized.
- * @param migrationProducers Migrations are run before any access to data can occur. Migrations
- * must be idempotent.
+ * @param migrations Migrations are run before any access to data can occur. Migrations must
+ * be idempotent.
* @param scope The scope in which IO operations and transform functions will execute.
*/
- @JvmOverloads
+ @JvmOverloads // Generate constructors for default params for java users.
fun <T> create(
produceFile: () -> File,
serializer: Serializer<T>,
corruptionHandler: ReplaceFileCorruptionHandler<T>? = null,
- migrationProducers: List<() -> DataMigration<T>> = listOf(),
+ migrations: List<DataMigration<T>> = listOf(),
scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
): DataStore<T> =
SingleProcessDataStore(
produceFile = produceFile,
serializer = serializer,
corruptionHandler = corruptionHandler ?: NoOpCorruptionHandler(),
- initTasksList = listOf(DataMigrationInitializer.getInitializer(migrationProducers)),
+ initTasksList = listOf(DataMigrationInitializer.getInitializer(migrations)),
scope = scope
)
}
\ No newline at end of file
diff --git a/datastore/datastore-core/src/main/java/androidx/datastore/migrations/SharedPreferencesMigration.kt b/datastore/datastore-core/src/main/java/androidx/datastore/migrations/SharedPreferencesMigration.kt
index 4a26721..63826ca 100644
--- a/datastore/datastore-core/src/main/java/androidx/datastore/migrations/SharedPreferencesMigration.kt
+++ b/datastore/datastore-core/src/main/java/androidx/datastore/migrations/SharedPreferencesMigration.kt
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-@file:JvmName("SharedPreferencesMigration")
-
package androidx.datastore.migrations
import android.content.Context
@@ -25,18 +23,19 @@
import java.io.IOException
/**
- * A DataMigration which migrates SharedPreferences to DataStore.
+ * DataMigration from SharedPreferences to DataStore.
*
- * Note: this accesses the SharedPreferences using MODE_PRIVATE.
- */
-internal val MIGRATE_ALL_KEYS = null
-
-/**
- * Returns a factory function which creates a SharedPreferences Data Migration.
+ * Example usage:
+ *
+ * val sharedPrefsMigration = SharedPreferencesMigration(
+ * context,
+ * mySharedPreferencesName
+ * ) { prefs: SharedPreferencesView, myData: MyData ->
+ * myData.toBuilder().setCounter(prefs.getCounter(COUNTER_KEY, default = 0)).build()
+ * }
*
* @param context Context used for getting SharedPreferences.
* @param sharedPreferencesName The name of the SharedPreferences.
- * @param migration The mapping function for the migration.
* @param keysToMigrate The list of keys to migrate. The keys will be mapped to datastore
* .Preferences with their same values. If the key is already present in the new Preferences, the key
* will not be migrated again. If the key is not present in the SharedPreferences it will not be
@@ -48,49 +47,93 @@
* SharedPreferences to begin with then the (potentially) empty SharedPreferences won't be
* cleaned up by this option. This functionality is best effort - if there is an issue deleting
* the SharedPreferences file it will be silently ignored.
+ * @param migrate maps SharedPreferences into T. Implementations should be idempotent
+ * since this may be called multiple times. See [DataMigration.migrate] for more
+ * information. The lambda accepts a SharedPreferencesView which is the view of the
+ * SharedPreferences to migrate from (limited to [keysToMigrate] and a T which represent
+ * the current data. The function must return the migrated data.
*/
-fun <T> SharedPreferencesMigration(
- context: Context,
- sharedPreferencesName: String,
- migration: MigrationFromSharedPreferences<T>,
+class SharedPreferencesMigration<T>
+@JvmOverloads // Generate constructors for default params for java users.
+constructor(
+ private val context: Context,
+ private val sharedPreferencesName: String,
keysToMigrate: Set<String>? = MIGRATE_ALL_KEYS,
- deleteEmptyPreferences: Boolean = true
-): () -> DataMigration<T> = {
- SharedPreferencesDataMigration(
- context,
- sharedPreferencesName,
- migration,
- keysToMigrate?.toMutableSet(),
- deleteEmptyPreferences
- )
-}
+ private val deleteEmptyPreferences: Boolean = true,
+ private val shouldRunMigration: suspend (T) -> Boolean = { true },
+ private val migrate: suspend (SharedPreferencesView, T) -> T
+) : DataMigration<T> {
-/**
- * User implemented migration interface. Contains logic for mapping SharedPreferences data to T.
- */
-interface MigrationFromSharedPreferences<T> {
- /**
- * Optional method that should return false if the migration should be skipped. This can
- * be useful to stop unnecessary calls into SharedPreferences. This can be implemented by
- * including a field in your data that specifies whether your migration has already been
- * run.
- *
- * @param currentData the current data (it might already populated from this or other
- * migrations)
- * @return Whether or not this migration should run.
- */
- suspend fun shouldMigrate(currentData: T): Boolean = true
+ private val sharedPrefs: SharedPreferences by lazy {
+ context.getSharedPreferences(sharedPreferencesName, Context.MODE_PRIVATE)
+ }
- /**
- * Perform the migration. Implementations should be idempotent since this may be called
- * multiple times. See {@code DataMigration#migrate} for more information.
- *
- * @param prefs the view of the SharedPreferences to migrate from.
- * @param currentData the current data (it might be populated from other migrations or from
- * manual changes before this migration was added to the app)
- * @return The migrated data.
- */
- suspend fun migrate(prefs: SharedPreferencesView, currentData: T): T
+ private val keySet: MutableSet<String> by lazy {
+ (keysToMigrate ?: sharedPrefs.all.keys).toMutableSet()
+ }
+
+ override suspend fun shouldMigrate(currentData: T): Boolean {
+ if (!shouldRunMigration(currentData)) {
+ return false
+ }
+
+ return keySet.any(sharedPrefs::contains)
+ }
+
+ override suspend fun migrate(currentData: T): T =
+ migrate(
+ SharedPreferencesView(
+ sharedPrefs,
+ keySet
+ ), currentData
+ )
+
+ @Throws(IOException::class)
+ override suspend fun cleanUp() {
+ val sharedPrefsEditor = sharedPrefs.edit()
+
+ for (key in keySet) {
+ sharedPrefsEditor.remove(key)
+ }
+
+ if (!sharedPrefsEditor.commit()) {
+ throw IOException(
+ "Unable to delete migrated keys from SharedPreferences: $sharedPreferencesName"
+ )
+ }
+
+ if (deleteEmptyPreferences && sharedPrefs.all.isEmpty()) {
+ deleteSharedPreferences(context, sharedPreferencesName)
+ }
+
+ keySet.clear()
+ }
+
+ private fun deleteSharedPreferences(context: Context, name: String) {
+ if (android.os.Build.VERSION.SDK_INT >= 24) {
+ if (!context.deleteSharedPreferences(name)) {
+ throw IOException("Unable to delete SharedPreferences: $name")
+ }
+ return
+ }
+
+ // Context.deleteSharedPreferences is SDK 24+, so we have to reproduce the definition
+ val prefsFile = getSharedPrefsFile(context, name)
+ val prefsBackup = getSharedPrefsBackup(prefsFile)
+
+ // Silently continue if we aren't able to delete the Shared Preferences File.
+ prefsFile.delete()
+ prefsBackup.delete()
+ }
+
+ // ContextImpl.getSharedPreferencesPath is private, so we have to reproduce the definition
+ private fun getSharedPrefsFile(context: Context, name: String): File {
+ val prefsDir = File(context.applicationInfo.dataDir, "shared_prefs")
+ return File(prefsDir, "$name.xml")
+ }
+
+ // SharedPreferencesImpl.makeBackupFile is private, so we have to reproduce the definition
+ private fun getSharedPrefsBackup(prefsFile: File) = File(prefsFile.path + ".bak")
}
/**
@@ -183,81 +226,4 @@
}
}
-private class SharedPreferencesDataMigration<T> internal constructor(
- private val context: Context,
- private val sharedPreferencesName: String,
- private val migration: MigrationFromSharedPreferences<T>,
- keysToMigrate: MutableSet<String>?,
- private val deleteEmptyPreferences: Boolean
-) : DataMigration<T> {
- private val sharedPrefs: SharedPreferences by lazy {
- context.getSharedPreferences(sharedPreferencesName, Context.MODE_PRIVATE)
- }
-
- private val keySet: MutableSet<String> by lazy {
- keysToMigrate ?: sharedPrefs.all.keys.toMutableSet()
- }
-
- override suspend fun shouldMigrate(currentData: T): Boolean {
- if (!migration.shouldMigrate(currentData)) {
- return false
- }
-
- return keySet.any(sharedPrefs::contains)
- }
-
- override suspend fun migrate(currentData: T): T =
- migration.migrate(
- SharedPreferencesView(
- sharedPrefs,
- keySet
- ), currentData
- )
-
- @Throws(IOException::class)
- override suspend fun cleanUp() {
- val sharedPrefsEditor = sharedPrefs.edit()
-
- for (key in keySet) {
- sharedPrefsEditor.remove(key)
- }
-
- if (!sharedPrefsEditor.commit()) {
- throw IOException(
- "Unable to delete migrated keys from SharedPreferences: $sharedPreferencesName"
- )
- }
-
- if (deleteEmptyPreferences && sharedPrefs.all.isEmpty()) {
- deleteSharedPreferences(context, sharedPreferencesName)
- }
-
- keySet.clear()
- }
-
- private fun deleteSharedPreferences(context: Context, name: String) {
- if (android.os.Build.VERSION.SDK_INT >= 24) {
- if (!context.deleteSharedPreferences(name)) {
- throw IOException("Unable to delete SharedPreferences: $name")
- }
- return
- }
-
- // Context.deleteSharedPreferences is SDK 24+, so we have to reproduce the definition
- val prefsFile = getSharedPrefsFile(context, name)
- val prefsBackup = getSharedPrefsBackup(prefsFile)
-
- // Silently continue if we aren't able to delete the Shared Preferences File.
- prefsFile.delete()
- prefsBackup.delete()
- }
-
- // ContextImpl.getSharedPreferencesPath is private, so we have to reproduce the definition
- private fun getSharedPrefsFile(context: Context, name: String): File {
- val prefsDir = File(context.applicationInfo.dataDir, "shared_prefs")
- return File(prefsDir, "$name.xml")
- }
-
- // SharedPreferencesImpl.makeBackupFile is private, so we have to reproduce the definition
- private fun getSharedPrefsBackup(prefsFile: File) = File(prefsFile.path + ".bak")
-}
+internal val MIGRATE_ALL_KEYS = null
diff --git a/datastore/datastore-core/src/test/java/androidx/datastore/DataMigrationInitializerTest.kt b/datastore/datastore-core/src/test/java/androidx/datastore/DataMigrationInitializerTest.kt
index 0729f0f..93eaf0d 100644
--- a/datastore/datastore-core/src/test/java/androidx/datastore/DataMigrationInitializerTest.kt
+++ b/datastore/datastore-core/src/test/java/androidx/datastore/DataMigrationInitializerTest.kt
@@ -54,7 +54,7 @@
val store = newDataStore(
initTasksList = listOf(
DataMigrationInitializer.getInitializer(
- listOf { migrateTo100 }
+ listOf(migrateTo100)
)
)
)
@@ -70,7 +70,7 @@
val store = newDataStore(
initTasksList = listOf(
DataMigrationInitializer.getInitializer(
- listOf({ migratePlus2 }, { migratePlus3 })
+ listOf(migratePlus2, migratePlus3)
)
)
)
@@ -90,7 +90,7 @@
val store = newDataStore(
initTasksList = listOf(
- DataMigrationInitializer.getInitializer(listOf({ noOpMigration }))
+ DataMigrationInitializer.getInitializer(listOf(noOpMigration))
)
)
@@ -114,7 +114,7 @@
val store = newDataStore(
initTasksList = listOf(
- DataMigrationInitializer.getInitializer(listOf({ noOpMigration }))
+ DataMigrationInitializer.getInitializer(listOf(noOpMigration))
)
)
@@ -140,7 +140,7 @@
serializer.failingWrite = true
val store = newDataStore(
initTasksList = listOf(
- DataMigrationInitializer.getInitializer(listOf({ noOpMigration }))
+ DataMigrationInitializer.getInitializer(listOf(noOpMigration))
),
serializer = serializer
)
@@ -162,7 +162,7 @@
val store = newDataStore(
initTasksList = listOf(
- DataMigrationInitializer.getInitializer(listOf({ cleanUpFailingMigration }))
+ DataMigrationInitializer.getInitializer(listOf(cleanUpFailingMigration))
)
)
@@ -175,42 +175,13 @@
val store = newDataStore(
initTasksList = listOf(
- DataMigrationInitializer.getInitializer(listOf({ neverRunMigration }))
+ DataMigrationInitializer.getInitializer(listOf(neverRunMigration))
)
)
assertThat(store.data.first()).isEqualTo(0)
}
- @Test
- fun testNewDataMigrationUsedOnFailure() = runBlockingTest {
- val migrationFactory =
- {
- var byte: Byte = 99
- val migration = TestingDataMigration(migration = {
- val unmodifiedByte = byte
- byte = byte.inc()
- unmodifiedByte
- })
- migration
- }
-
- val store = newDataStore(
- initTasksList = listOf(
- DataMigrationInitializer.getInitializer(listOf(migrationFactory))
- ),
- serializer = serializer
- )
-
- serializer.failingWrite = true
-
- assertThrows<IOException> { store.data.first() }
-
- serializer.failingWrite = false
-
- assertThat(store.data.first()).isEqualTo(99)
- }
-
private fun newDataStore(
initTasksList: List<suspend (api: InitializerApi<Byte>) -> Unit> = listOf(),
serializer: TestingSerializer = TestingSerializer()
diff --git a/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt b/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt
index 4d17579..f58247c 100644
--- a/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt
+++ b/datastore/datastore-core/src/test/java/androidx/datastore/DataStoreFactoryTest.kt
@@ -85,26 +85,22 @@
val migratedByte = 1
- val migratePlus2 = {
- object : DataMigration<Byte> {
+ val migratePlus2 = object : DataMigration<Byte> {
override suspend fun shouldMigrate(currentData: Byte) = true
override suspend fun migrate(currentData: Byte) = currentData.inc().inc()
override suspend fun cleanUp() {}
}
- }
- val migrateMinus1 = {
- object : DataMigration<Byte> {
+ val migrateMinus1 = object : DataMigration<Byte> {
override suspend fun shouldMigrate(currentData: Byte) = true
override suspend fun migrate(currentData: Byte) = currentData.dec()
override suspend fun cleanUp() {}
}
- }
val store = factory.create(
produceFile = { testFile },
- migrationProducers = listOf(migratePlus2, migrateMinus1),
+ migrations = listOf(migratePlus2, migrateMinus1),
scope = dataStoreScope,
serializer = TestingSerializer()
)
diff --git a/datastore/datastore-preferences/api/current.txt b/datastore/datastore-preferences/api/current.txt
index 53a9826..217726b 100644
--- a/datastore/datastore-preferences/api/current.txt
+++ b/datastore/datastore-preferences/api/current.txt
@@ -3,8 +3,8 @@
public final class PreferenceDataStoreFactory {
ctor public PreferenceDataStoreFactory();
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>> migrationProducers = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>> migrationProducers = listOf());
+ method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
+ method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
}
@@ -40,8 +40,10 @@
method public androidx.datastore.preferences.Preferences empty();
}
- public final class SharedPreferencesToPreferencesKt {
- method public static kotlin.jvm.functions.Function0<androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = SharedPreferencesToPreferences.MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ public final class SharedPreferencesMigrationKt {
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS);
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName);
}
}
diff --git a/datastore/datastore-preferences/api/public_plus_experimental_current.txt b/datastore/datastore-preferences/api/public_plus_experimental_current.txt
index 53a9826..217726b 100644
--- a/datastore/datastore-preferences/api/public_plus_experimental_current.txt
+++ b/datastore/datastore-preferences/api/public_plus_experimental_current.txt
@@ -3,8 +3,8 @@
public final class PreferenceDataStoreFactory {
ctor public PreferenceDataStoreFactory();
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>> migrationProducers = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>> migrationProducers = listOf());
+ method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
+ method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
}
@@ -40,8 +40,10 @@
method public androidx.datastore.preferences.Preferences empty();
}
- public final class SharedPreferencesToPreferencesKt {
- method public static kotlin.jvm.functions.Function0<androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = SharedPreferencesToPreferences.MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ public final class SharedPreferencesMigrationKt {
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS);
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName);
}
}
diff --git a/datastore/datastore-preferences/api/restricted_current.txt b/datastore/datastore-preferences/api/restricted_current.txt
index 53a9826..217726b 100644
--- a/datastore/datastore-preferences/api/restricted_current.txt
+++ b/datastore/datastore-preferences/api/restricted_current.txt
@@ -3,8 +3,8 @@
public final class PreferenceDataStoreFactory {
ctor public PreferenceDataStoreFactory();
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>> migrationProducers = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
- method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends kotlin.jvm.functions.Function0<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>>> migrationProducers = listOf());
+ method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf(), kotlinx.coroutines.CoroutineScope scope = CoroutineScope(Dispatchers.IO + SupervisorJob()));
+ method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null, java.util.List<? extends androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> migrations = listOf());
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile, androidx.datastore.handlers.ReplaceFileCorruptionHandler<androidx.datastore.preferences.Preferences>? corruptionHandler = null);
method public androidx.datastore.DataStore<androidx.datastore.preferences.Preferences> create(kotlin.jvm.functions.Function0<? extends java.io.File> produceFile);
}
@@ -40,8 +40,10 @@
method public androidx.datastore.preferences.Preferences empty();
}
- public final class SharedPreferencesToPreferencesKt {
- method public static kotlin.jvm.functions.Function0<androidx.datastore.DataMigration<androidx.datastore.preferences.Preferences>> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = SharedPreferencesToPreferences.MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ public final class SharedPreferencesMigrationKt {
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS, boolean deleteEmptyPreferences = true);
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName, java.util.Set<java.lang.String>? keysToMigrate = MIGRATE_ALL_KEYS);
+ method public static androidx.datastore.migrations.SharedPreferencesMigration<androidx.datastore.preferences.Preferences> SharedPreferencesMigration(android.content.Context context, String sharedPreferencesName);
}
}
diff --git a/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
index 10f9c23..c92da6e 100644
--- a/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
+++ b/datastore/datastore-preferences/src/androidTest/java/androidx/datastore/preferences/SharedPreferencesToPreferencesTest.kt
@@ -391,11 +391,11 @@
}
private fun getDataStoreWithMigrations(
- migrationProducers: List<() -> DataMigration<Preferences>>
+ migrations: List<DataMigration<Preferences>>
): DataStore<Preferences> {
return PreferenceDataStoreFactory().create(
produceFile = { datastoreFile },
- migrationProducers = migrationProducers,
+ migrations = migrations,
scope = TestCoroutineScope()
)
}
diff --git a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
index 5c77987..7de4135 100644
--- a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
+++ b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/PreferenceDataStoreFactory.kt
@@ -43,16 +43,16 @@
* @param corruptionHandler The corruptionHandler is invoked if DataStore encounters a [CorruptionException] when
* attempting to read data. CorruptionExceptions are thrown by serializers when data can
* not be de-serialized.
- * @param migrationProducers Migrations are run before any access to data can occur. Each
+ * @param migrations are run before any access to data can occur. Each
* producer and migration may be run more than once whether or not it already succeeded
* (potentially because another migration failed or a write to disk failed.)
* @param scope The scope in which IO operations and transform functions will execute.
*/
- @JvmOverloads
+ @JvmOverloads // Generate methods for default params for java users.
fun create(
produceFile: () -> File,
corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null,
- migrationProducers: List<() -> DataMigration<Preferences>> = listOf(),
+ migrations: List<DataMigration<Preferences>> = listOf(),
scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
): DataStore<Preferences> =
dataStoreFactory.create(
@@ -66,7 +66,7 @@
},
serializer = PreferencesSerializer,
corruptionHandler = corruptionHandler,
- migrationProducers = migrationProducers,
+ migrations = migrations,
scope = scope
)
}
\ No newline at end of file
diff --git a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/SharedPreferencesMigration.kt b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/SharedPreferencesMigration.kt
new file mode 100644
index 0000000..0e2a46c
--- /dev/null
+++ b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/SharedPreferencesMigration.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 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.datastore.preferences
+
+import android.content.Context
+import androidx.datastore.migrations.SharedPreferencesView
+import androidx.datastore.migrations.SharedPreferencesMigration
+
+/**
+ * Creates a SharedPreferencesMigration for DataStore<Preferences>.
+ *
+ * @param context Context used for getting SharedPreferences.
+ * @param sharedPreferencesName The name of the SharedPreferences.
+ * @param keysToMigrate The list of keys to migrate. The keys will be mapped to datastore.Preferences with
+ * their same values. If the key is already present in the new Preferences, the key
+ * will not be migrated again. If the key is not present in the SharedPreferences it
+ * will not be migrated. If keysToMigrate is not set, all keys will be migrated from the existing
+ * SharedPreferences.
+ * @param deleteEmptyPreferences If enabled and the SharedPreferences are empty (i.e. no remaining
+ * keys) after this migration runs, the leftover SharedPreferences file is deleted. Note that
+ * this cleanup runs only if the migration itself runs, i.e., if the keys were never in
+ * SharedPreferences to begin with then the (potentially) empty SharedPreferences
+ * won't be cleaned up by this option. This functionality is best effort - if there
+ * is an issue deleting the SharedPreferences file it will be silently ignored.
+ *
+ * TODO(rohitsat): determine whether to remove the deleteEmptyPreferences option.
+ */
+@JvmOverloads // Generate methods for default params for java users.
+fun SharedPreferencesMigration(
+ context: Context,
+ sharedPreferencesName: String,
+ keysToMigrate: Set<String>? = MIGRATE_ALL_KEYS,
+ deleteEmptyPreferences: Boolean = true
+): SharedPreferencesMigration<Preferences> {
+ return SharedPreferencesMigration(
+ context = context,
+ sharedPreferencesName = sharedPreferencesName,
+ keysToMigrate = keysToMigrate,
+ deleteEmptyPreferences = deleteEmptyPreferences,
+ shouldRunMigration = { prefs ->
+ // If any key hasn't been migrated to currentData, we can't skip the migration. If
+ // the key set is not specified, we can't skip the migration.
+ keysToMigrate?.any { it !in prefs } ?: true
+ },
+ migrate = { sharedPrefs: SharedPreferencesView, currentData: Preferences ->
+ // prefs.getAll is already filtered to our key set.
+ val preferencesToMigrate =
+ sharedPrefs.getAll().filter { (key, _) -> key !in currentData }
+
+ val preferencesBuilder = currentData.toBuilder()
+ for ((key, value) in preferencesToMigrate) {
+ when (value) {
+ is Boolean -> preferencesBuilder.setBoolean(key, value)
+ is Float -> preferencesBuilder.setFloat(key, value)
+ is Int -> preferencesBuilder.setInt(key, value)
+ is Long -> preferencesBuilder.setLong(key, value)
+ is String -> preferencesBuilder.setString(key, value)
+ is Set<*> ->
+ @Suppress("UNCHECKED_CAST")
+ preferencesBuilder.setStringSet(key, value.toSet() as Set<String>)
+ }
+ }
+
+ preferencesBuilder.build()
+ })
+}
+
+internal val MIGRATE_ALL_KEYS = null
\ No newline at end of file
diff --git a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/SharedPreferencesToPreferences.kt b/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/SharedPreferencesToPreferences.kt
deleted file mode 100644
index 0a70ea3..0000000
--- a/datastore/datastore-preferences/src/main/java/androidx/datastore/preferences/SharedPreferencesToPreferences.kt
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2020 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.datastore.preferences
-
-import android.content.Context
-import androidx.datastore.DataMigration
-import androidx.datastore.migrations.MigrationFromSharedPreferences
-import androidx.datastore.migrations.SharedPreferencesView
-import androidx.datastore.migrations.SharedPreferencesMigration
-
-/**
- * Creates a SharedPreferencesMigration for DataStore<Preferences>.
- *
- * @param context Context used for getting SharedPreferences.
- * @param sharedPreferencesName The name of the SharedPreferences.
- * @param keysToMigrate The list of keys to migrate. The keys will be mapped to datastore.Preferences with
- * their same values. If the key is already present in the new Preferences, the key
- * will not be migrated again. If the key is not present in the SharedPreferences it
- * will not be migrated. If keysToMigrate is not set, all keys will be migrated from the existing
- * SharedPreferences.
- * @param deleteEmptyPreferences If enabled and the SharedPreferences are empty (i.e. no remaining
- * keys) after this migration runs, the leftover SharedPreferences file is deleted. Note that
- * this cleanup runs only if the migration itself runs, i.e., if the keys were never in
- * SharedPreferences to begin with then the (potentially) empty SharedPreferences
- * won't be cleaned up by this option. This functionality is best effort - if there
- * is an issue deleting the SharedPreferences file it will be silently ignored.
- */
-fun SharedPreferencesMigration(
- context: Context,
- sharedPreferencesName: String,
- keysToMigrate: Set<String>? = SharedPreferencesToPreferences.MIGRATE_ALL_KEYS,
- deleteEmptyPreferences: Boolean = true
-): () -> DataMigration<Preferences> {
- return SharedPreferencesMigration(
- context,
- sharedPreferencesName,
- SharedPreferencesToPreferences(keysToMigrate),
- keysToMigrate,
- deleteEmptyPreferences
- )
-}
-
-/**
- * A DataMigration which migrates SharedPreferences to DataStore.
- *
- * Note: this accesses the SharedPreferences using MODE_PRIVATE.
- */
-internal class SharedPreferencesToPreferences(
- private val keysToMigrate: Set<String>?
-) : MigrationFromSharedPreferences<Preferences> {
-
- companion object {
- internal val MIGRATE_ALL_KEYS = null
- }
-
- override suspend fun shouldMigrate(currentData: Preferences): Boolean {
- if (keysToMigrate == null) {
- // We need to migrate all keys from the SharedPreferences.
- return true
- }
-
- // If any key hasn't been migrated to currentData, we can't skip the migration.
- return keysToMigrate.any { it !in currentData }
- }
-
- override suspend fun migrate(
- prefs: SharedPreferencesView,
- currentData: Preferences
- ): Preferences {
- // prefs.getAll is already filtered to our key set.
- val preferencesToMigrate = prefs.getAll().filter { (key, _) -> key !in currentData }
-
- val preferencesBuilder = currentData.toBuilder()
- for ((key, value) in preferencesToMigrate) {
- when (value) {
- is Boolean -> preferencesBuilder.setBoolean(key, value)
- is Float -> preferencesBuilder.setFloat(key, value)
- is Int -> preferencesBuilder.setInt(key, value)
- is Long -> preferencesBuilder.setLong(key, value)
- is String -> preferencesBuilder.setString(key, value)
- is Set<*> ->
- @Suppress("UNCHECKED_CAST")
- preferencesBuilder.setStringSet(key, value.toSet() as Set<String>)
- }
- }
-
- return preferencesBuilder.build()
- }
-}
\ No newline at end of file
diff --git a/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt b/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
index e200d12..7ae14dc 100644
--- a/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
+++ b/datastore/datastore-preferences/src/test/java/androidx/datastore/preferences/PreferenceDataStoreFactoryTest.kt
@@ -91,30 +91,27 @@
.setBoolean("boolean_key", true)
.build()
- val migrateTo5 = {
- object : DataMigration<Preferences> {
- override suspend fun shouldMigrate(currentData: Preferences) = true
+ val migrateTo5 = object : DataMigration<Preferences> {
+ override suspend fun shouldMigrate(currentData: Preferences) = true
- override suspend fun migrate(currentData: Preferences) =
- currentData.toBuilder().setString("string_key", "value").build()
+ override suspend fun migrate(currentData: Preferences) =
+ currentData.toBuilder().setString("string_key", "value").build()
- override suspend fun cleanUp() {}
- }
+ override suspend fun cleanUp() {}
}
- val migratePlus1 = {
- object : DataMigration<Preferences> {
- override suspend fun shouldMigrate(currentData: Preferences) = true
- override suspend fun migrate(currentData: Preferences) =
- currentData.toBuilder().setBoolean("boolean_key", true).build()
+ val migratePlus1 = object : DataMigration<Preferences> {
+ override suspend fun shouldMigrate(currentData: Preferences) = true
- override suspend fun cleanUp() {}
- }
+ override suspend fun migrate(currentData: Preferences) =
+ currentData.toBuilder().setBoolean("boolean_key", true).build()
+
+ override suspend fun cleanUp() {}
}
val store = factory.create(
produceFile = { testFile },
- migrationProducers = listOf(migrateTo5, migratePlus1),
+ migrations = listOf(migrateTo5, migratePlus1),
scope = dataStoreScope
)
diff --git a/enterprise/feedback/api/1.1.0-alpha01.txt b/enterprise/feedback/api/1.1.0-alpha01.txt
index 1cd14ea..4a23dc1 100644
--- a/enterprise/feedback/api/1.1.0-alpha01.txt
+++ b/enterprise/feedback/api/1.1.0-alpha01.txt
@@ -25,11 +25,21 @@
method public abstract androidx.enterprise.feedback.KeyedAppState.KeyedAppStateBuilder setSeverity(int);
}
+ public interface KeyedAppStatesCallback {
+ method public void onResult(int, Throwable?);
+ field public static final int STATUS_EXCEEDED_BUFFER_ERROR = 3; // 0x3
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_TRANSACTION_TOO_LARGE_ERROR = 2; // 0x2
+ field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+ }
+
public abstract class KeyedAppStatesReporter {
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context);
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context, java.util.concurrent.Executor);
- method public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
+ method @Deprecated public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
}
public abstract class KeyedAppStatesService extends android.app.Service {
diff --git a/enterprise/feedback/api/current.txt b/enterprise/feedback/api/current.txt
index 1cd14ea..4a23dc1 100644
--- a/enterprise/feedback/api/current.txt
+++ b/enterprise/feedback/api/current.txt
@@ -25,11 +25,21 @@
method public abstract androidx.enterprise.feedback.KeyedAppState.KeyedAppStateBuilder setSeverity(int);
}
+ public interface KeyedAppStatesCallback {
+ method public void onResult(int, Throwable?);
+ field public static final int STATUS_EXCEEDED_BUFFER_ERROR = 3; // 0x3
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_TRANSACTION_TOO_LARGE_ERROR = 2; // 0x2
+ field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+ }
+
public abstract class KeyedAppStatesReporter {
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context);
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context, java.util.concurrent.Executor);
- method public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
+ method @Deprecated public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
}
public abstract class KeyedAppStatesService extends android.app.Service {
diff --git a/enterprise/feedback/api/public_plus_experimental_1.1.0-alpha01.txt b/enterprise/feedback/api/public_plus_experimental_1.1.0-alpha01.txt
index 1cd14ea..4a23dc1 100644
--- a/enterprise/feedback/api/public_plus_experimental_1.1.0-alpha01.txt
+++ b/enterprise/feedback/api/public_plus_experimental_1.1.0-alpha01.txt
@@ -25,11 +25,21 @@
method public abstract androidx.enterprise.feedback.KeyedAppState.KeyedAppStateBuilder setSeverity(int);
}
+ public interface KeyedAppStatesCallback {
+ method public void onResult(int, Throwable?);
+ field public static final int STATUS_EXCEEDED_BUFFER_ERROR = 3; // 0x3
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_TRANSACTION_TOO_LARGE_ERROR = 2; // 0x2
+ field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+ }
+
public abstract class KeyedAppStatesReporter {
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context);
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context, java.util.concurrent.Executor);
- method public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
+ method @Deprecated public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
}
public abstract class KeyedAppStatesService extends android.app.Service {
diff --git a/enterprise/feedback/api/public_plus_experimental_current.txt b/enterprise/feedback/api/public_plus_experimental_current.txt
index 1cd14ea..4a23dc1 100644
--- a/enterprise/feedback/api/public_plus_experimental_current.txt
+++ b/enterprise/feedback/api/public_plus_experimental_current.txt
@@ -25,11 +25,21 @@
method public abstract androidx.enterprise.feedback.KeyedAppState.KeyedAppStateBuilder setSeverity(int);
}
+ public interface KeyedAppStatesCallback {
+ method public void onResult(int, Throwable?);
+ field public static final int STATUS_EXCEEDED_BUFFER_ERROR = 3; // 0x3
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_TRANSACTION_TOO_LARGE_ERROR = 2; // 0x2
+ field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+ }
+
public abstract class KeyedAppStatesReporter {
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context);
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context, java.util.concurrent.Executor);
- method public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
+ method @Deprecated public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
}
public abstract class KeyedAppStatesService extends android.app.Service {
diff --git a/enterprise/feedback/api/restricted_1.1.0-alpha01.txt b/enterprise/feedback/api/restricted_1.1.0-alpha01.txt
index 1cd14ea..4a23dc1 100644
--- a/enterprise/feedback/api/restricted_1.1.0-alpha01.txt
+++ b/enterprise/feedback/api/restricted_1.1.0-alpha01.txt
@@ -25,11 +25,21 @@
method public abstract androidx.enterprise.feedback.KeyedAppState.KeyedAppStateBuilder setSeverity(int);
}
+ public interface KeyedAppStatesCallback {
+ method public void onResult(int, Throwable?);
+ field public static final int STATUS_EXCEEDED_BUFFER_ERROR = 3; // 0x3
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_TRANSACTION_TOO_LARGE_ERROR = 2; // 0x2
+ field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+ }
+
public abstract class KeyedAppStatesReporter {
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context);
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context, java.util.concurrent.Executor);
- method public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
+ method @Deprecated public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
}
public abstract class KeyedAppStatesService extends android.app.Service {
diff --git a/enterprise/feedback/api/restricted_current.txt b/enterprise/feedback/api/restricted_current.txt
index 1cd14ea..4a23dc1 100644
--- a/enterprise/feedback/api/restricted_current.txt
+++ b/enterprise/feedback/api/restricted_current.txt
@@ -25,11 +25,21 @@
method public abstract androidx.enterprise.feedback.KeyedAppState.KeyedAppStateBuilder setSeverity(int);
}
+ public interface KeyedAppStatesCallback {
+ method public void onResult(int, Throwable?);
+ field public static final int STATUS_EXCEEDED_BUFFER_ERROR = 3; // 0x3
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ field public static final int STATUS_TRANSACTION_TOO_LARGE_ERROR = 2; // 0x2
+ field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
+ }
+
public abstract class KeyedAppStatesReporter {
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context);
method public static androidx.enterprise.feedback.KeyedAppStatesReporter create(android.content.Context, java.util.concurrent.Executor);
- method public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public abstract void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
+ method @Deprecated public abstract void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>, androidx.enterprise.feedback.KeyedAppStatesCallback?);
}
public abstract class KeyedAppStatesService extends android.app.Service {
diff --git a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/BufferedServiceConnection.java b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/BufferedServiceConnection.java
index f8d21aa..adc9ee3 100644
--- a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/BufferedServiceConnection.java
+++ b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/BufferedServiceConnection.java
@@ -16,6 +16,9 @@
package androidx.enterprise.feedback;
+import static androidx.enterprise.feedback.KeyedAppStatesCallback.STATUS_EXCEEDED_BUFFER_ERROR;
+import static androidx.enterprise.feedback.KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR;
+import static androidx.enterprise.feedback.KeyedAppStatesCallback.STATUS_UNKNOWN_ERROR;
import static androidx.enterprise.feedback.KeyedAppStatesReporter.canPackageReceiveAppStates;
import android.content.ComponentName;
@@ -26,7 +29,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
-import android.util.Log;
+import android.os.TransactionTooLargeException;
import androidx.annotation.VisibleForTesting;
@@ -45,8 +48,6 @@
*/
class BufferedServiceConnection {
- private static final String LOG_TAG = "BufferedServiceConnecti";
-
@VisibleForTesting
static final int MAX_BUFFER_SIZE = 100;
@@ -62,7 +63,7 @@
boolean mIsDead = false;
private boolean mHasBound = false;
@SuppressWarnings("WeakerAccess") /* synthetic access */
- final Queue<Message> mBuffer = new ArrayDeque<>();
+ final Queue<SendableMessage> mBuffer = new ArrayDeque<>();
@SuppressWarnings("WeakerAccess") /* synthetic access */
final Executor mExecutor;
@@ -119,6 +120,9 @@
mExecutor.execute(new Runnable() {
@Override
public void run() {
+ // If this is now dead then the messages should not be sent, report
+ // success
+ reportSuccessOnBufferedMessages();
mIsDead = true;
}
});
@@ -136,6 +140,9 @@
mMessenger = new Messenger(service);
sendBufferedMessages();
} else {
+ // If this is now dead then the messages should not be sent, report
+ // success
+ reportSuccessOnBufferedMessages();
mIsDead = true;
}
}
@@ -149,6 +156,13 @@
}
}
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ void reportSuccessOnBufferedMessages() {
+ while (!mBuffer.isEmpty()) {
+ mBuffer.poll().onSuccess();
+ }
+ }
+
@Override
public void onServiceDisconnected(ComponentName componentName) {
mExecutor.execute(new Runnable() {
@@ -169,14 +183,17 @@
* <p>The queue is capped at 100 messages. If 100 messages are already queued when send is
* called and a connection is not established, the earliest message in the queue will be lost.
*/
- void send(Message message) {
+ void send(SendableMessage message) {
if (mIsDead) {
+ // Nothing will send on this connection, so we need to report success to allow it to
+ // resolve.
+ message.onSuccess();
return;
}
if (mMessenger == null) {
while (mBuffer.size() >= MAX_BUFFER_SIZE) {
- mBuffer.poll();
+ mBuffer.poll().dealWithError(STATUS_EXCEEDED_BUFFER_ERROR, /* throwable= */ null);
}
mBuffer.add(message);
return;
@@ -186,11 +203,14 @@
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
- void trySendMessage(Message message) {
+ void trySendMessage(SendableMessage message) {
try {
- mMessenger.send(message);
+ mMessenger.send(message.createStateMessage());
+ message.onSuccess();
+ } catch (TransactionTooLargeException e) {
+ message.dealWithError(STATUS_TRANSACTION_TOO_LARGE_ERROR, e);
} catch (RemoteException e) {
- Log.e(LOG_TAG, "Error sending message", e);
+ message.dealWithError(STATUS_UNKNOWN_ERROR, e);
}
}
diff --git a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporter.java b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporter.java
index 216a807..f771489 100644
--- a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporter.java
+++ b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporter.java
@@ -25,9 +25,9 @@
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.Bundle;
-import android.os.Message;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -88,29 +88,48 @@
}
@Override
+ @Deprecated
public void setStates(@NonNull Collection<KeyedAppState> states) {
- setStates(states, false);
+ setStates(states, /* callback= */ null);
}
- private void setStates(final Collection<KeyedAppState> states, final boolean immediate) {
+ @Override
+ public void setStates(@NonNull Collection<KeyedAppState> states,
+ @Nullable KeyedAppStatesCallback callback) {
+ setStates(states, callback, /* immediate= */ false);
+ }
+
+ private void setStates(final Collection<KeyedAppState> states,
+ final KeyedAppStatesCallback callback, final boolean immediate) {
mExecutor.execute(new Runnable() {
@Override
public void run() {
if (states.isEmpty()) {
+ if (callback != null) {
+ callback.onResult(
+ KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+ }
return;
}
unbindOldBindings();
bind();
- send(buildStatesBundle(states), immediate);
+ send(buildStatesBundle(states), callback, immediate);
}
});
}
@Override
+ @Deprecated
public void setStatesImmediate(@NonNull Collection<KeyedAppState> states) {
- setStates(states, true);
+ setStatesImmediate(states, /* callback= */ null);
+ }
+
+ @Override
+ public void setStatesImmediate(@NonNull Collection<KeyedAppState> states,
+ @Nullable KeyedAppStatesCallback callback) {
+ setStates(states, callback, /* immediate= */ true);
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
@@ -233,17 +252,14 @@
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
- void send(Bundle appStatesBundle, boolean immediate) {
- for (BufferedServiceConnection serviceConnection : mServiceConnections.values()) {
- // Messages cannot be reused so we create a copy for each service connection.
- serviceConnection.send(createStateMessage(appStatesBundle, immediate));
+ void send(
+ Bundle appStatesBundle, @Nullable KeyedAppStatesCallback callback, boolean immediate) {
+ if (callback != null) {
+ // Callback will receive multiple callbacks so we need to merge them into a single one.
+ callback = new KeyedAppStatesCallbackMerger(mServiceConnections.size(), callback);
}
- }
-
- private static Message createStateMessage(Bundle appStatesBundle, boolean immediate) {
- Message message = Message.obtain();
- message.what = immediate ? WHAT_IMMEDIATE_STATE : WHAT_STATE;
- message.obj = appStatesBundle;
- return message;
+ for (BufferedServiceConnection serviceConnection : mServiceConnections.values()) {
+ serviceConnection.send(new SendableMessage(appStatesBundle, callback, immediate));
+ }
}
}
diff --git a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesCallback.java b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesCallback.java
new file mode 100644
index 0000000..6030c7f
--- /dev/null
+++ b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesCallback.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 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.enterprise.feedback;
+
+import androidx.annotation.Nullable;
+
+import java.util.Collection;
+
+/**
+ * Interface used to listen for the result when using
+ * {@link KeyedAppStatesReporter#setStates(Collection, KeyedAppStatesCallback)} or
+ * {@link KeyedAppStatesReporter#setStatesImmediate(Collection, KeyedAppStatesCallback)}.
+ *
+ * <p>{@link #onResult(int, Throwable)} will only only report errors which occur inside this app.
+ * If a failure occurs in the Device Policy Controller then this will not be reported.
+ *
+ * <p>{@link #STATUS_SUCCESS} will be reported if the states are sent to all Device Policy
+ * Controllers.
+ */
+public interface KeyedAppStatesCallback {
+ /**
+ * Used when the states have been sent to all eligible receivers.
+ *
+ * <p>If there are 0 eligible receivers on the device, then this will be recorded as success.
+ */
+ int STATUS_SUCCESS = 0;
+
+ /** Used when an error has occurred which stopped the states being set that isn't covered by
+ * the other error types. */
+ int STATUS_UNKNOWN_ERROR = 1;
+
+ /** An error has occurred because the transaction setting the states has exceeded the Android
+ * binder limit (1MB). This can occur because the app is filling up the 1MB limit with other
+ * IPC calls, or because the size or number of states being set is too large.
+ */
+ int STATUS_TRANSACTION_TOO_LARGE_ERROR = 2;
+
+ /** An error occurred because the local app buffer was exceeded. This means too many setState
+ * or setStateImmediate calls have been made without a connection to the DPC being formed. */
+ int STATUS_EXCEEDED_BUFFER_ERROR = 3;
+
+ /**
+ * Called either when an error happens in this app, or when the states have been sent to all
+ * eligible receivers.
+ *
+ * <p>If there is an error, this will be called with the first error encountered.
+ *
+ * <p>If there are 0 eligible receivers on the device, then this will be recorded as success.
+ */
+ void onResult(int state, @Nullable Throwable throwable);
+}
diff --git a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesCallbackMerger.java b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesCallbackMerger.java
new file mode 100644
index 0000000..d63265d
--- /dev/null
+++ b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesCallbackMerger.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 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.enterprise.feedback;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Merge multiple {@link KeyedAppStatesCallback} instances into a single one.
+ *
+ * <p>This will report success once {@code numReceivers} success results have been received.
+ *
+ * <p>It will report an error once a single non-success result is received.
+ */
+class KeyedAppStatesCallbackMerger implements KeyedAppStatesCallback {
+
+ private boolean mHasReported = false;
+ private int mSuccesses;
+ private final int mNumReceivers;
+ private final KeyedAppStatesCallback mOriginalCallback;
+
+ KeyedAppStatesCallbackMerger(int numReceivers, KeyedAppStatesCallback originalCallback) {
+ mNumReceivers = numReceivers;
+ mOriginalCallback = originalCallback;
+
+ if (mNumReceivers == 0) {
+ mHasReported = true;
+ mOriginalCallback.onResult(STATUS_SUCCESS, /* throwable= */ null);
+ }
+ }
+
+ @Override
+ public void onResult(int state, @Nullable Throwable throwable) {
+ if (mHasReported) {
+ // Only report once
+ return;
+ }
+
+ if (state != STATUS_SUCCESS || ++mSuccesses >= mNumReceivers) {
+ mHasReported = true;
+ mOriginalCallback.onResult(state, throwable);
+ }
+ }
+}
diff --git a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesReporter.java b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesReporter.java
index f46aa74..7f8de94 100644
--- a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesReporter.java
+++ b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/KeyedAppStatesReporter.java
@@ -21,6 +21,7 @@
import android.os.Message;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import java.util.Collection;
import java.util.concurrent.Executor;
@@ -116,6 +117,13 @@
}
/**
+ * @deprecated use {@link #setStates(Collection, KeyedAppStatesCallback)} which reports
+ * errors.
+ */
+ @Deprecated
+ public abstract void setStates(@NonNull Collection<KeyedAppState> states);
+
+ /**
* Set app states to be sent to an EMM (enterprise mobility management). The EMM can then
* display this information to the management organization.
*
@@ -134,17 +142,38 @@
* <p>EMMs can access these states either directly in a custom DPC (device policy manager), via
* Android Management APIs, or via Play EMM APIs.
*
- * @see #setStatesImmediate(Collection)
+ * <p>{@link KeyedAppStatesCallback#onResult(int, Throwable)} will be called when an
+ * error occurs.
+ *
+ * @see #setStatesImmediate(Collection, KeyedAppStatesCallback)
*/
- public abstract void setStates(@NonNull Collection<KeyedAppState> states);
+ public void setStates(@NonNull Collection<KeyedAppState> states,
+ @Nullable KeyedAppStatesCallback callback) {
+ throw new UnsupportedOperationException();
+ }
/**
- * Performs the same function as {@link #setStates(Collection)}, except it
- * also requests that the states are immediately uploaded to be accessible
+ * @deprecated use {@link #setStatesImmediate(Collection, KeyedAppStatesCallback)} which
+ * reports errors.
+ */
+ @Deprecated
+ public abstract void setStatesImmediate(@NonNull Collection<KeyedAppState> states);
+
+ /**
+ * Performs the same function as {@link #setStates(Collection, KeyedAppStatesCallback)},
+ * except it also requests that the states are immediately uploaded to be accessible
* via server APIs.
*
* <p>The receiver is not obligated to meet this immediate upload request.
* For example, Play and Android Management APIs have daily quotas.
+ *
+ * <p>{@link KeyedAppStatesCallback#onResult(int, Throwable)} will be called
+ * when an error occurs.
+ *
+ * @see #setStates(Collection, KeyedAppStatesCallback)
*/
- public abstract void setStatesImmediate(@NonNull Collection<KeyedAppState> states);
+ public void setStatesImmediate(@NonNull Collection<KeyedAppState> states,
+ @Nullable KeyedAppStatesCallback callback) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/enterprise/feedback/src/main/java/androidx/enterprise/feedback/SendableMessage.java b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/SendableMessage.java
new file mode 100644
index 0000000..16fac5f
--- /dev/null
+++ b/enterprise/feedback/src/main/java/androidx/enterprise/feedback/SendableMessage.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 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.enterprise.feedback;
+
+import static androidx.enterprise.feedback.KeyedAppStatesReporter.WHAT_IMMEDIATE_STATE;
+import static androidx.enterprise.feedback.KeyedAppStatesReporter.WHAT_STATE;
+
+import android.os.Bundle;
+import android.os.Message;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+final class SendableMessage {
+ private static final String LOG_TAG = "SendableMessage";
+
+ private final Bundle mAppStatesBundle;
+ private final KeyedAppStatesCallback mCallback;
+ private final boolean mImmediate;
+
+ SendableMessage(@NonNull Bundle appStatesBundle, @Nullable KeyedAppStatesCallback callback,
+ boolean immediate) {
+ this.mAppStatesBundle = appStatesBundle;
+ this.mCallback = callback;
+ this.mImmediate = immediate;
+ }
+
+ @Nullable
+ KeyedAppStatesCallback getCallback() {
+ return mCallback;
+ }
+
+ Message createStateMessage() {
+ Message message = Message.obtain();
+ message.what = mImmediate ? WHAT_IMMEDIATE_STATE : WHAT_STATE;
+ message.obj = mAppStatesBundle;
+ return message;
+ }
+
+ void onSuccess() {
+ if (mCallback != null) {
+ mCallback.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+ }
+ }
+
+ void dealWithError(int errorType, @Nullable Throwable throwable) {
+ if (mCallback != null) {
+ mCallback.onResult(errorType, throwable);
+ } else {
+ Log.e(LOG_TAG, "Error sending message. error: " + errorType, throwable);
+ }
+ }
+}
diff --git a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/BufferedServiceConnectionTest.java b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/BufferedServiceConnectionTest.java
index f802a4d..99f24dd 100644
--- a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/BufferedServiceConnectionTest.java
+++ b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/BufferedServiceConnectionTest.java
@@ -33,6 +33,7 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
@@ -77,6 +78,8 @@
private final ComponentName mPhoneskyComponentName =
new ComponentName("com.android.vending", "");
+ private final TestKeyedAppStatesCallback mCallback = new TestKeyedAppStatesCallback();
+
@Before
public void setUp() {
setComponentBindingToTestHandler(mTestComponentName);
@@ -163,27 +166,50 @@
@SmallTest
public void sendMessage_bound_sends() {
mBufferedServiceConnection.bindService();
+ shadowOf(getMainLooper()).idle();
+ SendableMessage sendableMessage = buildTestMessage();
- mBufferedServiceConnection.send(buildTestMessage());
-
+ mBufferedServiceConnection.send(sendableMessage);
shadowOf(getMainLooper()).idle();
- // The test message is rebuilt as it is cleared after being sent
- assertMessagesEqual(buildTestMessage(), mTestHandler.latestMessage());
+ assertMessagesEqual(sendableMessage.createStateMessage(), mTestHandler.latestMessage());
+ }
+
+ @Test
+ @SmallTest
+ public void sendMessage_bound_reportsSuccess() {
+ mBufferedServiceConnection.bindService();
+ SendableMessage sendableMessage = buildTestMessage(mCallback);
+
+ mBufferedServiceConnection.send(sendableMessage);
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
}
@Test
@SmallTest
public void sendMessage_notBound_doesNotSend() {
- Message message = buildTestMessage();
+ SendableMessage sendableMessage = buildTestMessage();
- mBufferedServiceConnection.send(message);
+ mBufferedServiceConnection.send(sendableMessage);
assertThat(mTestHandler.latestMessage()).isNull();
}
@Test
@SmallTest
+ public void sendMessage_notBound_doesNotCallback() {
+ SendableMessage sendableMessage = buildTestMessage(mCallback);
+
+ mBufferedServiceConnection.send(sendableMessage);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(0);
+ }
+
+ @Test
+ @SmallTest
@Config(minSdk = 26)
public void sendMessage_isDead_doesNotSend() {
mBufferedServiceConnection.bindService();
@@ -196,6 +222,18 @@
@Test
@SmallTest
+ @Config(minSdk = 26)
+ public void sendMessage_isDead_reportsSuccess() {
+ mBufferedServiceConnection.bindService();
+ simulateDeadServiceConnection();
+
+ mBufferedServiceConnection.send(buildTestMessage(mCallback));
+
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
public void sendMessage_notBound_isNotDoPoOrPhonesky_doesNotSendWhenBound() {
setComponentBindingToTestHandler(mNotPhoneskyComponentName);
shadowOf(mDevicePolicyManager).setDeviceOwner(null);
@@ -203,12 +241,27 @@
mBufferedServiceConnection.send(buildTestMessage());
mBufferedServiceConnection.bindService();
+ shadowOf(getMainLooper()).idle();
assertThat(mTestHandler.latestMessage()).isNull();
}
@Test
@SmallTest
+ public void sendMessage_notBound_isNotDoPoOrPhonesky_reportsSuccessWhenBound() {
+ setComponentBindingToTestHandler(mNotPhoneskyComponentName);
+ shadowOf(mDevicePolicyManager).setDeviceOwner(null);
+ shadowOf(mDevicePolicyManager).setProfileOwner(null);
+ mBufferedServiceConnection.send(buildTestMessage(mCallback));
+
+ mBufferedServiceConnection.bindService();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
public void sendMessage_notBound_isNotDoPoOrPhonesky_isDeadWhenBound() {
setComponentBindingToTestHandler(mNotPhoneskyComponentName);
shadowOf(mDevicePolicyManager).setDeviceOwner(null);
@@ -216,7 +269,6 @@
mBufferedServiceConnection.send(buildTestMessage());
mBufferedServiceConnection.bindService();
-
shadowOf(getMainLooper()).idle();
assertThat(mBufferedServiceConnection.isDead()).isTrue();
@@ -226,42 +278,83 @@
@SmallTest
public void sendMessage_notBound_isDeviceOwner_sendsWhenBound() {
shadowOf(mDevicePolicyManager).setDeviceOwner(mTestComponentName);
- mBufferedServiceConnection.send(buildTestMessage());
+ SendableMessage sendableMessage = buildTestMessage();
+ mBufferedServiceConnection.send(sendableMessage);
mBufferedServiceConnection.bindService();
-
shadowOf(getMainLooper()).idle();
- // The test message is rebuilt as it is cleared after being sent.
- assertMessagesEqual(buildTestMessage(), mTestHandler.latestMessage());
+ assertMessagesEqual(sendableMessage.createStateMessage(), mTestHandler.latestMessage());
+ }
+
+ @Test
+ @SmallTest
+ public void sendMessage_notBound_isDeviceOwner_reportsSuccessWhenBound() {
+ shadowOf(mDevicePolicyManager).setDeviceOwner(mTestComponentName);
+ SendableMessage sendableMessage = buildTestMessage(mCallback);
+ mBufferedServiceConnection.send(sendableMessage);
+
+ mBufferedServiceConnection.bindService();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
}
@Test
@SmallTest
public void sendMessage_notBound_isProfileOwner_sendsWhenBound() {
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
- mBufferedServiceConnection.send(buildTestMessage());
+ SendableMessage sendableMessage = buildTestMessage();
+ mBufferedServiceConnection.send(sendableMessage);
mBufferedServiceConnection.bindService();
-
shadowOf(getMainLooper()).idle();
// The test message is rebuilt as it is cleared after being sent.
- assertMessagesEqual(buildTestMessage(), mTestHandler.latestMessage());
+ assertMessagesEqual(sendableMessage.createStateMessage(), mTestHandler.latestMessage());
+ }
+
+ @Test
+ @SmallTest
+ public void sendMessage_notBound_isProfileOwner_reportsSuccessWhenBound() {
+ shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
+ SendableMessage sendableMessage = buildTestMessage(mCallback);
+ mBufferedServiceConnection.send(sendableMessage);
+
+ mBufferedServiceConnection.bindService();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
}
@Test
@SmallTest
public void sendMessage_notBound_isPhonesky_sendsWhenBound() {
setComponentBindingToTestHandler(mPhoneskyComponentName);
- mBufferedServiceConnection.send(buildTestMessage());
+ SendableMessage sendableMessage = buildTestMessage();
+ mBufferedServiceConnection.send(sendableMessage);
mBufferedServiceConnection.bindService();
-
shadowOf(getMainLooper()).idle();
// The test message is rebuilt as it is cleared after being sent.
- assertMessagesEqual(buildTestMessage(), mTestHandler.latestMessage());
+ assertMessagesEqual(sendableMessage.createStateMessage(), mTestHandler.latestMessage());
+ }
+
+ @Test
+ @SmallTest
+ public void sendMessage_notBound_isPhonesky_reportsSuccessWhenBound() {
+ setComponentBindingToTestHandler(mPhoneskyComponentName);
+ SendableMessage sendableMessage = buildTestMessage(mCallback);
+ mBufferedServiceConnection.send(sendableMessage);
+
+ mBufferedServiceConnection.bindService();
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
}
@Test
@@ -294,6 +387,20 @@
@Test
@SmallTest
+ public void sendMessage_notBound_sendBeyondBufferLimit_skippedMessagesReportError() {
+ mBufferedServiceConnection.send(buildTestMessage(mCallback));
+
+ for (int i = 0; i < MAX_BUFFER_SIZE; i++) {
+ mBufferedServiceConnection.send(buildTestMessage());
+ }
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(
+ KeyedAppStatesCallback.STATUS_EXCEEDED_BUFFER_ERROR);
+ }
+
+ @Test
+ @SmallTest
public void isDead_isFalse() {
mBufferedServiceConnection.bindService();
assertThat(mBufferedServiceConnection.isDead()).isFalse();
@@ -357,11 +464,15 @@
service);
}
- private static Message buildTestMessage() {
- Message message = Message.obtain();
- message.arg1 = 100;
- message.arg2 = 200;
- return message;
+ private static SendableMessage buildTestMessage() {
+ return buildTestMessage(/* callback= */ null);
+ }
+
+ private static SendableMessage buildTestMessage(KeyedAppStatesCallback callback) {
+ Bundle bundle = new Bundle();
+ bundle.putInt("arg1", 100);
+ bundle.putInt("arg2", 200);
+ return new SendableMessage(bundle, /* callback= */ callback, /* immediate= */ false);
}
private static void assertMessagesEqual(Message expected, Message actual) {
diff --git a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporterTest.java b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporterTest.java
index 25d4590..76d2e9e 100644
--- a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporterTest.java
+++ b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/DefaultKeyedAppStatesReporterTest.java
@@ -87,6 +87,7 @@
private final KeyedAppState mState =
KeyedAppState.builder().setKey("key").setSeverity(KeyedAppState.SEVERITY_INFO).build();
+ private final TestKeyedAppStatesCallback mCallback = new TestKeyedAppStatesCallback();
@Test
@SmallTest
@@ -126,7 +127,7 @@
setTestHandlerReceivesStates();
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
Bundle appStatesBundle = buildStatesBundle(singleton(mState));
@@ -174,17 +175,41 @@
setTestHandlerReceivesStates();
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(Collections.<KeyedAppState>emptyList());
+ reporter.setStates(Collections.<KeyedAppState>emptyList(), /* callback= */ null);
assertThat(mTestHandler.latestMessage()).isNull();
}
@Test
@SmallTest
+ public void setEmpty_reportsSuccess() {
+ setTestHandlerReceivesStates();
+
+ KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStates(Collections.<KeyedAppState>emptyList(), /* callback= */ mCallback);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
public void setNotImmediate() {
setTestHandlerReceivesStates();
KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStates(singletonList(mState), /* callback= */ null);
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mTestHandler.latestMessage().what).isEqualTo(WHAT_STATE);
+ }
+
+ @Test
+ @SmallTest
+ public void setNotImmediateDeprecated() {
+ setTestHandlerReceivesStates();
+
+ KeyedAppStatesReporter reporter = getReporter(mContext);
reporter.setStates(singletonList(mState));
shadowOf(getMainLooper()).idle();
@@ -193,10 +218,35 @@
@Test
@SmallTest
+ public void setNotImmediate_reportsSuccess() {
+ setTestHandlerReceivesStates();
+
+ KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStates(singletonList(mState), /* callback= */ mCallback);
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
public void setImmediate() {
setTestHandlerReceivesStates();
KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStatesImmediate(singletonList(mState), /* callback= */ null);
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mTestHandler.latestMessage().what).isEqualTo(WHAT_IMMEDIATE_STATE);
+ }
+
+ @Test
+ @SmallTest
+ public void setImmediateDeprecated() {
+ setTestHandlerReceivesStates();
+
+ KeyedAppStatesReporter reporter = getReporter(mContext);
reporter.setStatesImmediate(singletonList(mState));
shadowOf(getMainLooper()).idle();
@@ -205,12 +255,27 @@
@Test
@SmallTest
+ public void setImmediate_reportsSuccess() {
+ setTestHandlerReceivesStates();
+
+ KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStatesImmediate(singletonList(mState), /* callback= */ mCallback);
+ shadowOf(getMainLooper()).idle();
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+
+ @Test
+ @SmallTest
public void set_doesNotGoToNormalApps() {
addComponentAsRespondingToAppStatesIntent(mTestComponentName);
setComponentBindingToHandler(mTestComponentName, mTestHandler);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
+ shadowOf(getMainLooper()).idle();
assertThat(mTestHandler.latestMessage()).isNull();
}
@@ -223,7 +288,7 @@
shadowOf(mDevicePolicyManager).setDeviceOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
assertThat(mTestHandler.latestMessage()).isNotNull();
@@ -237,7 +302,7 @@
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
assertThat(mTestHandler.latestMessage()).isNotNull();
@@ -251,7 +316,7 @@
setComponentBindingToHandler(phoneskyComponentName, mTestHandler);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
assertThat(mTestHandler.latestMessage()).isNotNull();
@@ -272,10 +337,9 @@
// Act
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
-
// Assert
assertThat(mTestHandler.latestMessage()).isNotNull();
assertThat(phoneskyTestHandler.latestMessage()).isNotNull();
@@ -283,13 +347,36 @@
@Test
@SmallTest
+ public void set_goesToMultiple_reportsSingleSuccess() {
+ // Arrange
+ addComponentAsRespondingToAppStatesIntent(mTestComponentName);
+ setComponentBindingToHandler(mTestComponentName, mTestHandler);
+ shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
+
+ ComponentName phoneskyComponentName = new ComponentName(PHONESKY_PACKAGE_NAME, "");
+ TestHandler phoneskyTestHandler = new TestHandler();
+ addComponentAsRespondingToAppStatesIntent(phoneskyComponentName);
+ setComponentBindingToHandler(phoneskyComponentName, phoneskyTestHandler);
+
+ // Act
+ KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStates(singletonList(mState), /* callback= */ mCallback);
+ shadowOf(getMainLooper()).idle();
+
+ // Assert
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
public void set_changeProfileOwner_goesToNewProfileOwner() {
// Arrange
addComponentAsRespondingToAppStatesIntent(mTestComponentName);
setComponentBindingToHandler(mTestComponentName, mTestHandler);
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
mTestHandler.reset();
ComponentName newComponentName = new ComponentName("second_test_package", "");
@@ -299,7 +386,7 @@
shadowOf(mDevicePolicyManager).setProfileOwner(newComponentName);
// Act
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
// Assert
@@ -315,7 +402,7 @@
setComponentBindingToHandler(mTestComponentName, mTestHandler);
shadowOf(mDevicePolicyManager).setDeviceOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
mTestHandler.reset();
ComponentName newComponentName = new ComponentName("second_test_package", "");
@@ -325,7 +412,7 @@
shadowOf(mDevicePolicyManager).setDeviceOwner(newComponentName);
// Act
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
// Assert
@@ -343,7 +430,7 @@
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
mTestHandler.reset();
@@ -354,7 +441,7 @@
simulateDeadServiceConnection();
// Act
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
// Assert
@@ -372,7 +459,7 @@
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
mTestHandler.reset();
@@ -383,7 +470,7 @@
simulateDisconnectingServiceConnection();
// Act
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
// Assert
@@ -401,14 +488,14 @@
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
mTestHandler.reset();
simulateDisconnectingServiceConnection();
// Act
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
// Assert
@@ -418,6 +505,28 @@
@Test
@SmallTest
@Config(minSdk = 26)
+ public void set_connectionHasDisconnected_doesNotCallback() {
+ // Arrange
+ addComponentAsRespondingToAppStatesIntent(mTestComponentName);
+ setComponentBindingToHandler(mTestComponentName, mTestHandler);
+ shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
+
+ KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStates(singletonList(mState), /* callback= */ null);
+ mTestHandler.reset();
+
+ simulateDisconnectingServiceConnection();
+
+ // Act
+ reporter.setStates(singletonList(mState), /* callback= */ mCallback);
+
+ // Assert
+ assertThat(mCallback.mTotalResults).isEqualTo(0);
+ }
+
+ @Test
+ @SmallTest
+ @Config(minSdk = 26)
public void set_sendsWhenReconnected() {
// Arrange
addComponentAsRespondingToAppStatesIntent(mTestComponentName);
@@ -425,11 +534,11 @@
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
mTestHandler.reset();
simulateDisconnectingServiceConnection();
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
// Act
simulateReconnectingServiceConnection();
@@ -441,6 +550,30 @@
@Test
@SmallTest
+ @Config(minSdk = 26)
+ public void set_reportsSuccessWhenReconnected() {
+ // Arrange
+ addComponentAsRespondingToAppStatesIntent(mTestComponentName);
+ setComponentBindingToHandler(mTestComponentName, mTestHandler);
+ shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
+
+ KeyedAppStatesReporter reporter = getReporter(mContext);
+ reporter.setStates(singletonList(mState), /* callback= */ null);
+ mTestHandler.reset();
+
+ simulateDisconnectingServiceConnection();
+ reporter.setStates(singletonList(mState), /* callback= */ mCallback);
+
+ // Act
+ simulateReconnectingServiceConnection();
+
+ // Assert
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
public void set_connectionHasReconnected_doesSend() {
// Arrange
addComponentAsRespondingToAppStatesIntent(mTestComponentName);
@@ -448,7 +581,7 @@
shadowOf(mDevicePolicyManager).setProfileOwner(mTestComponentName);
KeyedAppStatesReporter reporter = getReporter(mContext);
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
mTestHandler.reset();
// Change the component binding to ensure that it doesn't reconnect
@@ -458,7 +591,7 @@
simulateReconnectingServiceConnection();
// Act
- reporter.setStates(singletonList(mState));
+ reporter.setStates(singletonList(mState), /* callback= */ null);
shadowOf(getMainLooper()).idle();
// Assert
@@ -511,4 +644,26 @@
private KeyedAppStatesReporter getReporter(Context context) {
return new DefaultKeyedAppStatesReporter(context, mExecutor);
}
+
+ private static Collection<KeyedAppState> generateMaximumSizeStates() {
+ Collection<KeyedAppState> states = new ArrayList<>();
+ for (int i = 0; i < 500; i++) {
+ states.add(generateLargeState("key" + i));
+ }
+ return states;
+ }
+
+ private static KeyedAppState generateLargeState(String keySuffix) {
+ return KeyedAppState.builder()
+ .setKey(generateStringOfLength(
+ KeyedAppState.MAX_KEY_LENGTH - keySuffix.length()) + keySuffix)
+ .setSeverity(KeyedAppState.SEVERITY_INFO)
+ .setData(generateStringOfLength(KeyedAppState.MAX_DATA_LENGTH))
+ .setMessage(generateStringOfLength(KeyedAppState.MAX_MESSAGE_LENGTH))
+ .build();
+ }
+
+ private static String generateStringOfLength(int length) {
+ return String.format("%0" + length + "d", 0);
+ }
}
diff --git a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/KeyedAppStatesCallbackMergerTest.java b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/KeyedAppStatesCallbackMergerTest.java
new file mode 100644
index 0000000..e6305c7
--- /dev/null
+++ b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/KeyedAppStatesCallbackMergerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2020 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.enterprise.feedback;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests {@link KeyedAppStatesCallbackMerger}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+@Config(minSdk = 21)
+public class KeyedAppStatesCallbackMergerTest {
+
+ private final TestKeyedAppStatesCallback mCallback = new TestKeyedAppStatesCallback();
+ private final Throwable mTestThrowable = new IllegalArgumentException();
+
+ @Test
+ @SmallTest
+ public void notZeroExpected_noImmediateCallback() {
+ new KeyedAppStatesCallbackMerger(1, mCallback);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(0);
+ }
+
+ @Test
+ @SmallTest
+ public void zeroExpected_successCallbackImmediately() {
+ new KeyedAppStatesCallbackMerger(0, mCallback);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
+ public void oneExpected_successCallbackIsPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(1, mCallback);
+
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
+ public void twoExpected_firstSuccessCallbackIsNotPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(2, mCallback);
+
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(0);
+ }
+
+ @Test
+ @SmallTest
+ public void twoExpected_secondSuccessCallbackIsPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(2, mCallback);
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ @SmallTest
+ public void twoExpected_thirdSuccessCallbackIsNotPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(2, mCallback);
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ }
+
+ @Test
+ @SmallTest
+ public void oneExpected_failureCallbackIsPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(1, mCallback);
+
+ merger.onResult(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR);
+ }
+
+ @Test
+ @SmallTest
+ public void twoExpected_firstFailureCallbackIsPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(2, mCallback);
+
+ merger.onResult(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR);
+ }
+
+ @Test
+ @SmallTest
+ public void twoExpected_secondFailureCallbackIsNotPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(2, mCallback);
+ merger.onResult(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR, /* throwable= */ null);
+
+ merger.onResult(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR);
+ }
+
+ @Test
+ @SmallTest
+ public void twoExpected_alreadyFailed_laterSuccessCallbacksAreNotPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(2, mCallback);
+ merger.onResult(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR, /* throwable= */ null);
+
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+ merger.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR);
+ }
+
+ @Test
+ @SmallTest
+ public void throwableIsPassedThrough() {
+ KeyedAppStatesCallbackMerger merger =
+ new KeyedAppStatesCallbackMerger(1, mCallback);
+
+ merger.onResult(
+ KeyedAppStatesCallback.STATUS_TRANSACTION_TOO_LARGE_ERROR,
+ /* throwable= */ mTestThrowable);
+
+ assertThat(mCallback.mLatestThrowable).isEqualTo(mTestThrowable);
+ }
+}
diff --git a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/KeyedAppStatesReporterTest.java b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/KeyedAppStatesReporterTest.java
index 936dc29..1b83245 100644
--- a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/KeyedAppStatesReporterTest.java
+++ b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/KeyedAppStatesReporterTest.java
@@ -100,7 +100,7 @@
KeyedAppStatesReporter reporter =
KeyedAppStatesReporter.create(mContext, testExecutor);
- reporter.setStates(singleton(mState));
+ reporter.setStates(singleton(mState), /* callback= */ null);
assertThat(testExecutor.lastExecuted()).isNotNull();
}
diff --git a/enterprise/feedback/src/test/java/androidx/enterprise/feedback/TestKeyedAppStatesCallback.java b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/TestKeyedAppStatesCallback.java
new file mode 100644
index 0000000..37e05c9
--- /dev/null
+++ b/enterprise/feedback/src/test/java/androidx/enterprise/feedback/TestKeyedAppStatesCallback.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 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.enterprise.feedback;
+
+import androidx.annotation.Nullable;
+
+class TestKeyedAppStatesCallback implements KeyedAppStatesCallback {
+
+ int mTotalResults = 0;
+ int mLatestState = -1;
+ Throwable mLatestThrowable = null;
+
+ @Override
+ public void onResult(int state, @Nullable Throwable throwable) {
+ mTotalResults++;
+ mLatestState = state;
+ mLatestThrowable = throwable;
+ }
+}
diff --git a/enterprise/feedback/testing/api/1.1.0-alpha01.txt b/enterprise/feedback/testing/api/1.1.0-alpha01.txt
index beb926b..89ff8fd 100644
--- a/enterprise/feedback/testing/api/1.1.0-alpha01.txt
+++ b/enterprise/feedback/testing/api/1.1.0-alpha01.txt
@@ -10,8 +10,8 @@
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getOnDeviceKeyedAppStatesByKey();
method public java.util.List<androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStates();
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStatesByKey();
- method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
}
}
diff --git a/enterprise/feedback/testing/api/current.txt b/enterprise/feedback/testing/api/current.txt
index beb926b..89ff8fd 100644
--- a/enterprise/feedback/testing/api/current.txt
+++ b/enterprise/feedback/testing/api/current.txt
@@ -10,8 +10,8 @@
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getOnDeviceKeyedAppStatesByKey();
method public java.util.List<androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStates();
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStatesByKey();
- method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
}
}
diff --git a/enterprise/feedback/testing/api/public_plus_experimental_1.1.0-alpha01.txt b/enterprise/feedback/testing/api/public_plus_experimental_1.1.0-alpha01.txt
index beb926b..89ff8fd 100644
--- a/enterprise/feedback/testing/api/public_plus_experimental_1.1.0-alpha01.txt
+++ b/enterprise/feedback/testing/api/public_plus_experimental_1.1.0-alpha01.txt
@@ -10,8 +10,8 @@
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getOnDeviceKeyedAppStatesByKey();
method public java.util.List<androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStates();
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStatesByKey();
- method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
}
}
diff --git a/enterprise/feedback/testing/api/public_plus_experimental_current.txt b/enterprise/feedback/testing/api/public_plus_experimental_current.txt
index beb926b..89ff8fd 100644
--- a/enterprise/feedback/testing/api/public_plus_experimental_current.txt
+++ b/enterprise/feedback/testing/api/public_plus_experimental_current.txt
@@ -10,8 +10,8 @@
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getOnDeviceKeyedAppStatesByKey();
method public java.util.List<androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStates();
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStatesByKey();
- method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
}
}
diff --git a/enterprise/feedback/testing/api/restricted_1.1.0-alpha01.txt b/enterprise/feedback/testing/api/restricted_1.1.0-alpha01.txt
index beb926b..89ff8fd 100644
--- a/enterprise/feedback/testing/api/restricted_1.1.0-alpha01.txt
+++ b/enterprise/feedback/testing/api/restricted_1.1.0-alpha01.txt
@@ -10,8 +10,8 @@
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getOnDeviceKeyedAppStatesByKey();
method public java.util.List<androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStates();
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStatesByKey();
- method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
}
}
diff --git a/enterprise/feedback/testing/api/restricted_current.txt b/enterprise/feedback/testing/api/restricted_current.txt
index beb926b..89ff8fd 100644
--- a/enterprise/feedback/testing/api/restricted_current.txt
+++ b/enterprise/feedback/testing/api/restricted_current.txt
@@ -10,8 +10,8 @@
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getOnDeviceKeyedAppStatesByKey();
method public java.util.List<androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStates();
method public java.util.Map<java.lang.String!,androidx.enterprise.feedback.KeyedAppState!> getUploadedKeyedAppStatesByKey();
- method public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
- method public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStates(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
+ method @Deprecated public void setStatesImmediate(java.util.Collection<androidx.enterprise.feedback.KeyedAppState!>);
}
}
diff --git a/enterprise/feedback/testing/src/main/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporter.java b/enterprise/feedback/testing/src/main/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporter.java
index 8f9d908..9b221bd 100644
--- a/enterprise/feedback/testing/src/main/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporter.java
+++ b/enterprise/feedback/testing/src/main/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporter.java
@@ -17,6 +17,7 @@
package androidx.enterprise.feedback;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -54,24 +55,48 @@
Collections.synchronizedMap(new HashMap<String, KeyedAppState>());
private AtomicInteger mNumberOfUploads = new AtomicInteger();
+ /** @deprecated see {@link #setStates(Collection, KeyedAppStatesCallback)}. **/
@Override
+ @Deprecated
public void setStates(@NonNull Collection<KeyedAppState> states) {
+ setStates(states, /* callback= */ null);
+ }
+
+ /**
+ * Record the states set.
+ *
+ * <p>Does not enforce any limit on total size of states collection.
+ */
+ @Override
+ public void setStates(@NonNull Collection<KeyedAppState> states,
+ @Nullable KeyedAppStatesCallback callback) {
for (KeyedAppState state : states) {
mOnDeviceKeyedAppStates.add(state);
mOnDeviceKeyedAppStatesByKey.put(state.getKey(), state);
mKeyedAppStates.add(state);
mKeyedAppStatesByKey.put(state.getKey(), state);
}
+ if (callback != null) {
+ callback.onResult(KeyedAppStatesCallback.STATUS_SUCCESS, /* throwable= */ null);
+ }
+ }
+
+ /** @deprecated See {@link #setStatesImmediate(Collection, KeyedAppStatesCallback)}. **/
+ @Override
+ @Deprecated
+ public void setStatesImmediate(@NonNull Collection<KeyedAppState> states) {
+ setStatesImmediate(states, /* callback= */ null);
}
/**
* Record the set states and immediately mark all states as having been uploaded.
*
- * <p>Does not enforce any quota on uploading.
+ * <p>Does not enforce any quota on uploading, or limit on total size of states collection.
*/
@Override
- public void setStatesImmediate(@NonNull Collection<KeyedAppState> states) {
- setStates(states);
+ public void setStatesImmediate(@NonNull Collection<KeyedAppState> states,
+ @Nullable KeyedAppStatesCallback callback) {
+ setStates(states, callback);
upload();
}
diff --git a/enterprise/feedback/testing/src/test/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporterTest.java b/enterprise/feedback/testing/src/test/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporterTest.java
index be7ecdd..fe34f6a 100644
--- a/enterprise/feedback/testing/src/test/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporterTest.java
+++ b/enterprise/feedback/testing/src/test/java/androidx/enterprise/feedback/FakeKeyedAppStatesReporterTest.java
@@ -50,6 +50,8 @@
.setMessage("different-message")
.build();
+ private final TestKeyedAppStatesCallback mCallback = new TestKeyedAppStatesCallback();
+
@Test
public void beginsEmpty() {
FakeKeyedAppStatesReporter reporter = new FakeKeyedAppStatesReporter();
@@ -58,7 +60,30 @@
}
@Test
+ public void setStates_reportsSuccess() {
+ mReporter.setStates(singletonList(KEYED_APP_STATE), mCallback);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
+ public void setStatesImmediate_reportsSuccess() {
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), mCallback);
+
+ assertThat(mCallback.mTotalResults).isEqualTo(1);
+ assertThat(mCallback.mLatestState).isEqualTo(KeyedAppStatesCallback.STATUS_SUCCESS);
+ }
+
+ @Test
public void setStates_single_isRecordedInOnDeviceKeyedAppStates() {
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
+
+ assertThat(mReporter.getOnDeviceKeyedAppStates()).containsExactly(KEYED_APP_STATE);
+ }
+
+ @Test
+ public void setStates_deprecated_isRecordedInOnDeviceKeyedAppStates() {
mReporter.setStates(singletonList(KEYED_APP_STATE));
assertThat(mReporter.getOnDeviceKeyedAppStates()).containsExactly(KEYED_APP_STATE);
@@ -66,7 +91,7 @@
@Test
public void setStates_single_isRecordedInOnDeviceKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE);
@@ -76,7 +101,8 @@
@Test
public void setStates_multiple_isRecordedInOnDeviceKeyedAppStates() {
- mReporter.setStates(asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -84,7 +110,8 @@
@Test
public void setStates_multiple_isRecordedInOnDeviceKeyedAppStatesByKey() {
- mReporter.setStates(asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -98,9 +125,10 @@
@Test
public void setStates_alreadyPopulated_addsToOnDeviceKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -108,9 +136,10 @@
@Test
public void setStates_alreadyPopulated_addsToOnDeviceKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -124,9 +153,10 @@
@Test
public void setStates_sameKeyAsPrevious_addsToOnDeviceKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_MESSAGE);
@@ -134,9 +164,10 @@
@Test
public void setStates_sameKeyAsPrevious_replacesOnDeviceKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStatesByKey().get(KEYED_APP_STATE.getKey()))
.isEqualTo(KEYED_APP_STATE_DIFFERENT_MESSAGE);
@@ -144,38 +175,47 @@
@Test
public void setStatesImmediate_clearsOnDeviceKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStates()).isEmpty();
}
@Test
public void setStatesImmediate_clearsOnDeviceKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getOnDeviceKeyedAppStatesByKey().keySet()).isEmpty();
}
@Test
public void setStates_isNotRecordedInUploadedKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStates()).isEmpty();
}
@Test
public void setStates_isNotRecordedInUploadedKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStatesByKey()).isEmpty();
}
@Test
public void setStatesImmediate_single_isRecordedInUploadedKeyedAppStates() {
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
+
+ assertThat(mReporter.getUploadedKeyedAppStates()).containsExactly(KEYED_APP_STATE);
+ }
+
+ @Test
+ public void setStatesImmediate_deprecated_isRecordedInUploadedKeyedAppStates() {
mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
assertThat(mReporter.getUploadedKeyedAppStates()).containsExactly(KEYED_APP_STATE);
@@ -183,7 +223,7 @@
@Test
public void setStatesImmediate_single_isRecordedInUploadedKeyedAppStatesByKey() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE);
@@ -193,7 +233,8 @@
@Test
public void setStatesImmediate_multiple_isRecordedInUploadedKeyedAppStates() {
- mReporter.setStatesImmediate(asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -201,7 +242,8 @@
@Test
public void setStatesImmediate_multiple_isRecordedInUploadedKeyedAppStatesByKey() {
- mReporter.setStatesImmediate(asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -215,9 +257,10 @@
@Test
public void setStatesImmediate_alreadyPopulated_addsToUploadedKeyedAppStates() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -225,9 +268,10 @@
@Test
public void setStatesImmediate_alreadyPopulated_addsToUploadedKeyedAppStatesByKey() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -241,9 +285,10 @@
@Test
public void setStatesImmediate_sameKeyAsPrevious_addsToUploadedKeyedAppStates() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_MESSAGE);
@@ -251,9 +296,10 @@
@Test
public void setStatesImmediate_sameKeyAsPrevious_replacesUploadedKeyedAppStatesByKey() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE), /* callback= */ null);
assertThat(
mReporter.getUploadedKeyedAppStatesByKey().get(KEYED_APP_STATE.getKey()))
@@ -262,9 +308,10 @@
@Test
public void setStatesImmediate_uploadsPreviouslySetStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getUploadedKeyedAppStatesByKey())
.containsKey(KEYED_APP_STATE.getKey());
@@ -272,21 +319,21 @@
@Test
public void setStatesImmediate_incrementsNumberOfUploads() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
assertThat(mReporter.getNumberOfUploads()).isEqualTo(1);
}
@Test
public void setStates_single_isRecordedInKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
assertThat(mReporter.getKeyedAppStates()).containsExactly(KEYED_APP_STATE);
}
@Test
public void setStates_single_isRecordedInKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
assertThat(mReporter.getKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE);
@@ -296,7 +343,8 @@
@Test
public void setStates_multiple_isRecordedInKeyedAppStates() {
- mReporter.setStates(asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -304,7 +352,8 @@
@Test
public void setStates_multiple_isRecordedInKeyedAppStatesByKey() {
- mReporter.setStates(asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ asList(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -316,9 +365,10 @@
@Test
public void setStates_alreadyPopulated_addsToKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -326,9 +376,10 @@
@Test
public void setStates_alreadyPopulated_addsToKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getKeyedAppStatesByKey().values())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -340,9 +391,10 @@
@Test
public void setStates_sameKeyAsPrevious_addsToKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE), /* callback= */ null);
assertThat(mReporter.getKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_MESSAGE);
@@ -350,9 +402,10 @@
@Test
public void setStates_sameKeyAsPrevious_replacesKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_MESSAGE), /* callback= */ null);
assertThat(
mReporter.getKeyedAppStatesByKey().get(KEYED_APP_STATE.getKey()))
@@ -361,9 +414,10 @@
@Test
public void setStatesImmediate_doesNotClearKeyedAppStates() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getKeyedAppStates())
.containsExactly(KEYED_APP_STATE, KEYED_APP_STATE_DIFFERENT_KEY);
@@ -371,9 +425,10 @@
@Test
public void setStatesImmediate_doesNotClearKeyedAppStatesByKey() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(mReporter.getKeyedAppStatesByKey().keySet())
.containsExactly(KEYED_APP_STATE.getKey(), KEYED_APP_STATE_DIFFERENT_KEY.getKey());
@@ -381,21 +436,23 @@
@Test
public void getOnDeviceKeyedAppStates_returnsCopy() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
List<KeyedAppState> beforeOnDeviceKeyedAppStates = mReporter.getOnDeviceKeyedAppStates();
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(beforeOnDeviceKeyedAppStates).doesNotContain(KEYED_APP_STATE_DIFFERENT_KEY);
}
@Test
public void getOnDeviceKeyedAppStatesByKey_returnsCopy() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
Map<String, KeyedAppState> beforeOnDeviceKeyedAppStates =
mReporter.getOnDeviceKeyedAppStatesByKey();
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(beforeOnDeviceKeyedAppStates)
.doesNotContainKey(KEYED_APP_STATE_DIFFERENT_KEY.getKey());
@@ -403,21 +460,23 @@
@Test
public void getKeyedAppStates_returnsCopy() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
List<KeyedAppState> beforeKeyedAppStates = mReporter.getKeyedAppStates();
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(beforeKeyedAppStates).doesNotContain(KEYED_APP_STATE_DIFFERENT_KEY);
}
@Test
public void getKeyedAppStatesByKey_returnsCopy() {
- mReporter.setStates(singletonList(KEYED_APP_STATE));
+ mReporter.setStates(singletonList(KEYED_APP_STATE), /* callback= */ null);
Map<String, KeyedAppState> beforeKeyedAppStates =
mReporter.getKeyedAppStatesByKey();
- mReporter.setStates(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStates(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(beforeKeyedAppStates)
.doesNotContainKey(KEYED_APP_STATE_DIFFERENT_KEY.getKey());
@@ -425,21 +484,23 @@
@Test
public void getUploadedKeyedAppStates_returnsCopy() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
List<KeyedAppState> beforeUploadedKeyedAppStates = mReporter.getUploadedKeyedAppStates();
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(beforeUploadedKeyedAppStates).doesNotContain(KEYED_APP_STATE_DIFFERENT_KEY);
}
@Test
public void getUploadedKeyedAppStatesByKey_returnsCopy() {
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE));
+ mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE), /* callback= */ null);
Map<String, KeyedAppState> beforeUploadedKeyedAppStates =
mReporter.getUploadedKeyedAppStatesByKey();
- mReporter.setStatesImmediate(singletonList(KEYED_APP_STATE_DIFFERENT_KEY));
+ mReporter.setStatesImmediate(
+ singletonList(KEYED_APP_STATE_DIFFERENT_KEY), /* callback= */ null);
assertThat(beforeUploadedKeyedAppStates)
.doesNotContainKey(KEYED_APP_STATE_DIFFERENT_KEY.getKey());
diff --git a/enterprise/feedback/testing/src/test/java/androidx/enterprise/feedback/TestKeyedAppStatesCallback.java b/enterprise/feedback/testing/src/test/java/androidx/enterprise/feedback/TestKeyedAppStatesCallback.java
new file mode 100644
index 0000000..37e05c9
--- /dev/null
+++ b/enterprise/feedback/testing/src/test/java/androidx/enterprise/feedback/TestKeyedAppStatesCallback.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 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.enterprise.feedback;
+
+import androidx.annotation.Nullable;
+
+class TestKeyedAppStatesCallback implements KeyedAppStatesCallback {
+
+ int mTotalResults = 0;
+ int mLatestState = -1;
+ Throwable mLatestThrowable = null;
+
+ @Override
+ public void onResult(int state, @Nullable Throwable throwable) {
+ mTotalResults++;
+ mLatestState = state;
+ mLatestThrowable = throwable;
+ }
+}
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
index 2843ded..31abb96 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/BackStackStateTest.kt
@@ -269,9 +269,35 @@
val fm = fc.supportFragmentManager
val fragment = StrictViewFragment()
+
+ fm.beginTransaction()
+ .add(android.R.id.content, fragment)
+ .setReorderingAllowed(true)
+ .setMaxLifecycle(fragment, Lifecycle.State.INITIALIZED)
+ .commitNow()
+
+ assertThat(fragment.lifecycle.currentState).isEqualTo(Lifecycle.State.INITIALIZED)
+
+ assertThat(fragment.calledOnResume).isFalse()
+ }
+
+ @Test
+ @UiThreadTest
+ fun setMaxLifecycleInitializedAfterCreated() {
+ val viewModelStore = ViewModelStore()
+ val fc = activityRule.startupFragmentController(viewModelStore)
+
+ val fm = fc.supportFragmentManager
+
+ val fragment = StrictViewFragment()
+
+ fm.beginTransaction()
+ .add(android.R.id.content, fragment)
+ .setMaxLifecycle(fragment, Lifecycle.State.CREATED)
+ .commitNow()
+
try {
fm.beginTransaction()
- .add(android.R.id.content, fragment)
.setMaxLifecycle(fragment, Lifecycle.State.INITIALIZED)
.commitNow()
fail(
@@ -281,7 +307,10 @@
} catch (e: IllegalArgumentException) {
assertThat(e)
.hasMessageThat()
- .contains("Cannot set maximum Lifecycle below CREATED")
+ .contains(
+ "Cannot set maximum Lifecycle to INITIALIZED after the Fragment has been " +
+ "created"
+ )
}
}
}
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt
index 3edf294..346918f 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt
@@ -16,6 +16,7 @@
package androidx.fragment.app
+import androidx.fragment.app.test.EmptyFragmentTestActivity
import androidx.fragment.app.test.TestViewModel
import androidx.fragment.app.test.ViewModelActivity
import androidx.fragment.app.test.ViewModelActivity.ViewModelFragment
@@ -42,6 +43,60 @@
}
@Test
+ fun testMaxLifecycleInitializedFragment() {
+ with(ActivityScenario.launch(EmptyFragmentTestActivity::class.java)) {
+ withActivity {
+ val fragment = StrictFragment()
+ supportFragmentManager.beginTransaction()
+ .setReorderingAllowed(true)
+ .add(android.R.id.content, fragment)
+ .setMaxLifecycle(fragment, Lifecycle.State.INITIALIZED)
+ .commitNow()
+
+ try {
+ fragment.viewModelStore
+ } catch (e: IllegalStateException) {
+ assertThat(e).hasMessageThat().contains(
+ "Calling getViewModelStore() before a Fragment " +
+ "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is " +
+ "not supported"
+ )
+ }
+ }
+ }
+ }
+
+ @Test
+ fun testMaxLifecycleInitializedNestedFragment() {
+ with(ActivityScenario.launch(EmptyFragmentTestActivity::class.java)) {
+ withActivity {
+ val fragment = StrictFragment()
+ val childFragment = StrictFragment()
+
+ supportFragmentManager.beginTransaction()
+ .setReorderingAllowed(true)
+ .add(android.R.id.content, fragment)
+ .setMaxLifecycle(fragment, Lifecycle.State.INITIALIZED)
+ .commitNow()
+
+ fragment.childFragmentManager.beginTransaction()
+ .add(android.R.id.content, childFragment)
+ .commitNow()
+
+ try {
+ childFragment.viewModelStore
+ } catch (e: IllegalStateException) {
+ assertThat(e).hasMessageThat().contains(
+ "Calling getViewModelStore() before a Fragment " +
+ "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is " +
+ "not supported"
+ )
+ }
+ }
+ }
+ }
+
+ @Test
fun testSameActivityViewModels() {
with(ActivityScenario.launch(ViewModelActivity::class.java)) {
val activityModel = withActivity { activityModel }
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
index b095212..4bc88fb 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
@@ -248,9 +248,9 @@
throw new IllegalArgumentException("Cannot setMaxLifecycle for Fragment not attached to"
+ " FragmentManager " + mManager);
}
- if (!state.isAtLeast(Lifecycle.State.CREATED)) {
- throw new IllegalArgumentException("Cannot set maximum Lifecycle below "
- + Lifecycle.State.CREATED);
+ if (state == Lifecycle.State.INITIALIZED && fragment.mState > Fragment.INITIALIZING) {
+ throw new IllegalArgumentException("Cannot set maximum Lifecycle to " + state
+ + " after the Fragment has been created");
}
return super.setMaxLifecycle(fragment, state);
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index e7ebc3d..c7530f64 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -397,9 +397,22 @@
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
+ if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
+ throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
+ + "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
+ + "supported");
+ }
return mFragmentManager.getViewModelStore(this);
}
+
+ private int getMinimumMaxLifecycleState() {
+ if (mMaxState == Lifecycle.State.INITIALIZED || mParentFragment == null) {
+ return mMaxState.ordinal();
+ }
+ return Math.min(mMaxState.ordinal(), mParentFragment.getMinimumMaxLifecycleState());
+ }
+
/**
* {@inheritDoc}
*
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
index 13a25cf..00c1d0b 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -238,6 +238,9 @@
case CREATED:
maxState = Math.min(maxState, Fragment.CREATED);
break;
+ case INITIALIZED:
+ maxState = Math.min(maxState, Fragment.ATTACHED);
+ break;
default:
maxState = Math.min(maxState, Fragment.INITIALIZING);
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
index 7c6c6c72..ec4771f 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
@@ -454,9 +454,10 @@
* already above the received state, it will be forced down to the correct state.
*
* <p>The fragment provided must currently be added to the FragmentManager to have it's
- * Lifecycle state capped, or previously added as part of this transaction. The
- * {@link Lifecycle.State} passed in must at least be {@link Lifecycle.State#CREATED}, otherwise
- * an {@link IllegalArgumentException} will be thrown.</p>
+ * Lifecycle state capped, or previously added as part of this transaction. If the
+ * {@link Lifecycle.State#INITIALIZED} is passed in as the {@link Lifecycle.State} and the
+ * provided fragment has already moved beyond {@link Lifecycle.State#INITIALIZED}, an
+ * {@link IllegalArgumentException} will be thrown.</p>
*
* @param fragment the fragment to have it's state capped.
* @param state the ceiling state for the fragment.
diff --git a/leanback/leanback/src/androidTest/java/androidx/leanback/widget/GridWidgetTest.java b/leanback/leanback/src/androidTest/java/androidx/leanback/widget/GridWidgetTest.java
index 9627125..382e579 100644
--- a/leanback/leanback/src/androidTest/java/androidx/leanback/widget/GridWidgetTest.java
+++ b/leanback/leanback/src/androidTest/java/androidx/leanback/widget/GridWidgetTest.java
@@ -4902,6 +4902,70 @@
}
@Test
+ public void testAccessibilityFocusOutFrontEnd_actionsAvailable() throws Throwable {
+ Intent intent = new Intent();
+ intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+ R.layout.horizontal_linear);
+ int[] items = new int[5];
+ for (int i = 0; i < items.length; i++) {
+ items[i] = 300;
+ }
+ intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+ intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+ initActivity(intent);
+ mOrientation = BaseGridView.HORIZONTAL;
+ mNumRows = 1;
+ final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+ .getCompatAccessibilityDelegate();
+ final AccessibilityNodeInfoCompat info1 = AccessibilityNodeInfoCompat.obtain();
+ // Test not allowing going out both ends
+ mLayoutManager.setFocusOutAllowed(/* throughFront= */ false,
+ /* throughEnd= */ false);
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info1);
+ }
+ });
+ // When not allowing jumping out both end, handle action scroll backward/forward to block
+ // it.
+ if (Build.VERSION.SDK_INT >= 21) {
+ assertTrue(hasAction(info1,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT));
+ assertTrue(hasAction(info1,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT));
+ } else {
+ assertTrue(hasAction(info1,
+ AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD));
+ assertTrue(hasAction(info1,
+ AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD));
+ }
+ final AccessibilityNodeInfoCompat info2 = AccessibilityNodeInfoCompat.obtain();
+ // Test allowing focus to jump out at front when reaching front.
+ mLayoutManager.setFocusOutAllowed(/* throughFront= */ true,
+ /* throughEnd= */ false);
+ mActivityTestRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info2);
+ }
+ });
+ // When only allowing jumping out front, block action scroll backward when reaching front
+ // for Talkback to jump focus out.
+ if (Build.VERSION.SDK_INT >= 21) {
+ assertFalse(hasAction(info2,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT));
+ assertTrue(hasAction(info2,
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT));
+ } else {
+ assertFalse(hasAction(info2,
+ AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD));
+ assertTrue(hasAction(info2,
+ AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD));
+ }
+ }
+
+ @Test
public void testAccessibilitySaveContextCrash() throws Throwable {
Intent intent = new Intent();
intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
diff --git a/leanback/leanback/src/main/java/androidx/leanback/widget/GridLayoutManager.java b/leanback/leanback/src/main/java/androidx/leanback/widget/GridLayoutManager.java
index e15e2c9..3a86542 100644
--- a/leanback/leanback/src/main/java/androidx/leanback/widget/GridLayoutManager.java
+++ b/leanback/leanback/src/main/java/androidx/leanback/widget/GridLayoutManager.java
@@ -37,6 +37,7 @@
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
+import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AccelerateDecelerateInterpolator;
import androidx.annotation.VisibleForTesting;
@@ -3758,20 +3759,40 @@
}
}
}
- switch (translatedAction) {
- case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
- processPendingMovement(false);
- processSelectionMoves(false, -1);
- break;
- case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
- processPendingMovement(true);
- processSelectionMoves(false, 1);
- break;
+ boolean scrollingReachedBeginning = (mFocusPosition == 0
+ && translatedAction == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
+ boolean scrollingReachedEnd = (mFocusPosition == state.getItemCount() - 1
+ && translatedAction == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
+ if (scrollingReachedBeginning || scrollingReachedEnd) {
+ // Send a fake scroll completion event to notify Talkback that the scroll event was
+ // successful. Hence, Talkback will only look for next focus within the RecyclerView.
+ // Not sending this will result in Talkback classifying it as a failed scroll event, and
+ // will try to jump focus out of the RecyclerView.
+ // We know at this point that either focusOutFront or focusOutEnd is true (or both),
+ // because otherwise, we never hit ACTION_SCROLL_BACKWARD/FORWARD here.
+ sendTypeViewScrolledAccessibilityEvent();
+ } else {
+ switch (translatedAction) {
+ case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
+ processPendingMovement(false);
+ processSelectionMoves(false, -1);
+ break;
+ case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
+ processPendingMovement(true);
+ processSelectionMoves(false, 1);
+ break;
+ }
}
leaveContext();
return true;
}
+ private void sendTypeViewScrolledAccessibilityEvent() {
+ AccessibilityEvent event = AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED);
+ mBaseGridView.onInitializeAccessibilityEvent(event);
+ mBaseGridView.requestSendAccessibilityEvent(mBaseGridView, event);
+ }
+
/*
* Move mFocusPosition multiple steps on the same row in main direction.
* Stops when moves are all consumed or reach first/last visible item.
@@ -3826,45 +3847,58 @@
return moves;
}
+ private void addA11yActionMovingBackward(AccessibilityNodeInfoCompat info,
+ boolean reverseFlowPrimary) {
+ if (Build.VERSION.SDK_INT >= 23) {
+ if (mOrientation == HORIZONTAL) {
+ info.addAction(reverseFlowPrimary
+ ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
+ .ACTION_SCROLL_RIGHT :
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat
+ .ACTION_SCROLL_LEFT);
+ } else {
+ info.addAction(
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP);
+ }
+ } else {
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
+ }
+ info.setScrollable(true);
+ }
+
+ private void addA11yActionMovingForward(AccessibilityNodeInfoCompat info,
+ boolean reverseFlowPrimary) {
+ if (Build.VERSION.SDK_INT >= 23) {
+ if (mOrientation == HORIZONTAL) {
+ info.addAction(reverseFlowPrimary
+ ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
+ .ACTION_SCROLL_LEFT :
+ AccessibilityNodeInfoCompat.AccessibilityActionCompat
+ .ACTION_SCROLL_RIGHT);
+ } else {
+ info.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat
+ .ACTION_SCROLL_DOWN);
+ }
+ } else {
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
+ }
+ info.setScrollable(true);
+ }
+
@Override
public void onInitializeAccessibilityNodeInfo(Recycler recycler, State state,
AccessibilityNodeInfoCompat info) {
saveContext(recycler, state);
int count = state.getItemCount();
+ // reverseFlowPrimary is whether we are in LTR/RTL mode.
boolean reverseFlowPrimary = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0;
- if (count > 1 && !isItemFullyVisible(0)) {
- if (Build.VERSION.SDK_INT >= 23) {
- if (mOrientation == HORIZONTAL) {
- info.addAction(reverseFlowPrimary
- ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
- .ACTION_SCROLL_RIGHT :
- AccessibilityNodeInfoCompat.AccessibilityActionCompat
- .ACTION_SCROLL_LEFT);
- } else {
- info.addAction(
- AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP);
- }
- } else {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
- }
- info.setScrollable(true);
+ // If focusOutFront/focusOutEnd is false, override Talkback in handling
+ // backward/forward actions by adding such actions to supported action list.
+ if ((mFlag & PF_FOCUS_OUT_FRONT) == 0 || (count > 1 && !isItemFullyVisible(0))) {
+ addA11yActionMovingBackward(info, reverseFlowPrimary);
}
- if (count > 1 && !isItemFullyVisible(count - 1)) {
- if (Build.VERSION.SDK_INT >= 23) {
- if (mOrientation == HORIZONTAL) {
- info.addAction(reverseFlowPrimary
- ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
- .ACTION_SCROLL_LEFT :
- AccessibilityNodeInfoCompat.AccessibilityActionCompat
- .ACTION_SCROLL_RIGHT);
- } else {
- info.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat
- .ACTION_SCROLL_DOWN);
- }
- } else {
- info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
- }
- info.setScrollable(true);
+ if ((mFlag & PF_FOCUS_OUT_END) == 0 || (count > 1 && !isItemFullyVisible(count - 1))) {
+ addA11yActionMovingForward(info, reverseFlowPrimary);
}
final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo =
AccessibilityNodeInfoCompat.CollectionInfoCompat
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
index c4e8d90..73fa138 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
@@ -202,7 +202,7 @@
notifyRequestFailed(requestId, REASON_INVALID_COMMAND);
return;
}
- sessionRecord.release();
+ sessionRecord.release(/*shouldUnselect=*/true);
}
@Override
@@ -502,7 +502,7 @@
sessionRecord = mSessionRecords.remove(sessionId);
}
if (sessionRecord != null) {
- sessionRecord.release();
+ sessionRecord.release(/*shouldUnselect=*/false);
}
}
@@ -747,7 +747,7 @@
}
}
- public void release() {
+ public void release(boolean shouldUnselect) {
if (!mIsReleased) {
// Release member controllers
if ((mFlags & (SESSION_FLAG_MR2 | SESSION_FLAG_GROUP))
@@ -755,7 +755,7 @@
updateMemberRouteControllers(null, mSessionInfo, null);
}
- if ((mFlags & SESSION_FLAG_MR2) != 0) {
+ if (shouldUnselect) {
mController.onUnselect(MediaRouter.UNSELECT_REASON_STOPPED);
mController.onRelease();
}
diff --git a/paging/common/api/current.txt b/paging/common/api/current.txt
index efc3cb0..31c6f43 100644
--- a/paging/common/api/current.txt
+++ b/paging/common/api/current.txt
@@ -132,9 +132,6 @@
enum_constant public static final androidx.paging.LoadType REFRESH;
}
- public final class PageEventKt {
- }
-
@Deprecated public abstract class PageKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key,Value> {
ctor @Deprecated public PageKeyedDataSource();
method @Deprecated public abstract void loadAfter(androidx.paging.PageKeyedDataSource.LoadParams<Key> params, androidx.paging.PageKeyedDataSource.LoadCallback<Key,Value> callback);
diff --git a/paging/common/api/public_plus_experimental_current.txt b/paging/common/api/public_plus_experimental_current.txt
index 179870c..b3261e2 100644
--- a/paging/common/api/public_plus_experimental_current.txt
+++ b/paging/common/api/public_plus_experimental_current.txt
@@ -134,9 +134,6 @@
enum_constant public static final androidx.paging.LoadType REFRESH;
}
- public final class PageEventKt {
- }
-
@Deprecated public abstract class PageKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key,Value> {
ctor @Deprecated public PageKeyedDataSource();
method @Deprecated public abstract void loadAfter(androidx.paging.PageKeyedDataSource.LoadParams<Key> params, androidx.paging.PageKeyedDataSource.LoadCallback<Key,Value> callback);
diff --git a/paging/common/api/restricted_current.txt b/paging/common/api/restricted_current.txt
index efc3cb0..31c6f43 100644
--- a/paging/common/api/restricted_current.txt
+++ b/paging/common/api/restricted_current.txt
@@ -132,9 +132,6 @@
enum_constant public static final androidx.paging.LoadType REFRESH;
}
- public final class PageEventKt {
- }
-
@Deprecated public abstract class PageKeyedDataSource<Key, Value> extends androidx.paging.DataSource<Key,Value> {
ctor @Deprecated public PageKeyedDataSource();
method @Deprecated public abstract void loadAfter(androidx.paging.PageKeyedDataSource.LoadParams<Key> params, androidx.paging.PageKeyedDataSource.LoadCallback<Key,Value> callback);
diff --git a/paging/common/src/main/kotlin/androidx/paging/CachedPageEventFlow.kt b/paging/common/src/main/kotlin/androidx/paging/CachedPageEventFlow.kt
index e509aeb..1b25396 100644
--- a/paging/common/src/main/kotlin/androidx/paging/CachedPageEventFlow.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/CachedPageEventFlow.kt
@@ -54,6 +54,7 @@
* This flag ensures that we do not try to collect from upstream more than once.
*/
private val collectedFromSource = AtomicBoolean(false)
+
/**
* Shared upstream.
* Note that, if upstream flow ends, re-subscribing to this will not re-collect from upstream
@@ -165,6 +166,7 @@
private val list = FlattenedPageEventStorage<T>()
private var snapshots = listOf<TemporaryDownstream<T>>()
private val lock = Mutex()
+
/**
* Record the event.
* This sends the event into storage but also into any other active TemporaryDownstream.
@@ -233,15 +235,11 @@
when (event.loadType) {
LoadType.PREPEND -> {
placeholdersBefore = event.placeholdersRemaining
- repeat(event.count) {
- pages.removeFirst()
- }
+ repeat(event.pageCount) { pages.removeFirst() }
}
LoadType.APPEND -> {
placeholdersAfter = event.placeholdersRemaining
- repeat(event.count) {
- pages.removeLast()
- }
+ repeat(event.pageCount) { pages.removeLast() }
}
else -> throw IllegalArgumentException("Page drop type must be prepend or append")
}
diff --git a/paging/common/src/main/kotlin/androidx/paging/PageEvent.kt b/paging/common/src/main/kotlin/androidx/paging/PageEvent.kt
index ec9b15a..47bbb74 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PageEvent.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PageEvent.kt
@@ -19,8 +19,6 @@
import androidx.paging.LoadType.APPEND
import androidx.paging.LoadType.PREPEND
import androidx.paging.LoadType.REFRESH
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
/**
* Events in the stream from paging fetch logic to UI.
@@ -28,6 +26,8 @@
* Every event sent to the UI is a PageEvent, and will be processed atomically.
*/
internal sealed class PageEvent<T : Any> {
+ // Intentional to prefer Refresh, Prepend, Append constructors from Companion.
+ @Suppress("DataClassPrivateConstructor")
data class Insert<T : Any> private constructor(
val loadType: LoadType,
val pages: List<TransformablePage<T>>,
@@ -62,10 +62,10 @@
override suspend fun <R : Any> map(transform: suspend (T) -> R): PageEvent<R> = mapPages {
TransformablePage(
- originalPageOffset = it.originalPageOffset,
+ originalPageOffsets = it.originalPageOffsets,
data = it.data.map { item -> transform(item) },
- originalPageSize = it.originalPageSize,
- originalIndices = it.originalIndices
+ hintOriginalPageOffset = it.hintOriginalPageOffset,
+ hintOriginalIndices = it.hintOriginalIndices
)
}
@@ -76,16 +76,16 @@
val originalIndices = mutableListOf<Int>()
it.data.forEachIndexed { index, t ->
data += transform(t)
- val indexToStore = it.originalIndices?.get(index) ?: index
+ val indexToStore = it.hintOriginalIndices?.get(index) ?: index
while (originalIndices.size < data.size) {
originalIndices.add(indexToStore)
}
}
TransformablePage(
- originalPageOffset = it.originalPageOffset,
+ originalPageOffsets = it.originalPageOffsets,
data = data,
- originalPageSize = it.originalPageSize,
- originalIndices = originalIndices
+ hintOriginalPageOffset = it.hintOriginalPageOffset,
+ hintOriginalIndices = originalIndices
)
}
@@ -95,14 +95,14 @@
it.data.forEachIndexed { index, t ->
if (predicate(t)) {
data.add(t)
- originalIndices.add(it.originalIndices?.get(index) ?: index)
+ originalIndices.add(it.hintOriginalIndices?.get(index) ?: index)
}
}
TransformablePage(
- originalPageOffset = it.originalPageOffset,
+ originalPageOffsets = it.originalPageOffsets,
data = data,
- originalPageSize = it.originalPageSize,
- originalIndices = originalIndices
+ hintOriginalPageOffset = it.hintOriginalPageOffset,
+ hintOriginalIndices = originalIndices
)
}
@@ -148,17 +148,26 @@
data class Drop<T : Any>(
val loadType: LoadType,
- val count: Int,
+ /**
+ * Smallest [TransformablePage.originalPageOffsets] to drop; inclusive.
+ */
+ val minPageOffset: Int,
+ /**
+ * Largest [TransformablePage.originalPageOffsets] to drop; inclusive
+ */
+ val maxPageOffset: Int,
val placeholdersRemaining: Int
) : PageEvent<T>() {
init {
require(loadType != REFRESH) { "Drop load type must be PREPEND or APPEND" }
- require(count >= 0) { "Drop count must be > 0, but was $count" }
+ require(pageCount > 0) { "Drop count must be > 0, but was $pageCount" }
require(placeholdersRemaining >= 0) {
"Invalid placeholdersRemaining $placeholdersRemaining"
}
}
+
+ val pageCount get() = maxPageOffset - minPageOffset + 1
}
data class LoadStateUpdate<T : Any>(
@@ -184,100 +193,3 @@
open suspend fun filter(predicate: suspend (T) -> Boolean): PageEvent<T> = this
}
-
-private fun <T> MutableList<T>.removeFirst(count: Int) {
- repeat(count) { removeAt(0) }
-}
-
-private fun <T> MutableList<T>.removeLast(count: Int) {
- repeat(count) { removeAt(lastIndex) }
-}
-
-internal inline fun <R : Any, T : R, PageStash, Stash> Flow<PageEvent<T>>.scan(
- crossinline createStash: () -> Stash,
- crossinline createPageStash: (TransformablePage<T>) -> PageStash,
- crossinline createInsert: (PageEvent.Insert<T>, List<PageStash>, Stash) -> PageEvent.Insert<R>,
- crossinline createDrop: (PageEvent.Drop<T>, List<PageStash>, Stash) -> PageEvent.Drop<R>
-): Flow<PageEvent<R>> {
- var stash: Stash = createStash()
- val pageStash = mutableListOf<PageStash>()
- return map { event ->
- @Suppress("UNCHECKED_CAST")
- when (event) {
- is PageEvent.Insert<T> -> {
- // use the stash before modifying it, since we may want to inspect adjacent pages
- val output = createInsert(event, pageStash, stash)
- val pageStashes = event.pages.map { createPageStash(it) }
- when (event.loadType) {
- REFRESH -> {
- check(pageStash.isEmpty())
- pageStash.addAll(pageStashes)
- }
- PREPEND -> {
- pageStash.addAll(0, pageStashes)
- }
- APPEND -> {
- pageStash.addAll(pageStash.size, pageStashes)
- }
- }
- output
- }
- is PageEvent.Drop -> {
- if (event.loadType == PREPEND) {
- pageStash.removeFirst(event.count)
- } else {
- pageStash.removeLast(event.count)
- }
- // use the stash after modifying it
- createDrop(event, pageStash, stash)
- }
- is PageEvent.LoadStateUpdate -> event as PageEvent<R>
- }
- }
-}
-
-/**
- * Transforms the Flow to an output-equivalent Flow, which does not have empty pages.
- *
- * This can be used before accessing adjacent pages, to ensure adjacent pages have context in
- * them.
- *
- * Note that we don't drop events, since those can contain other important state
- */
-internal fun <T : Any> Flow<PageEvent<T>>.removeEmptyPages(): Flow<PageEvent<T>> = scan(
- createStash = { Unit },
- createPageStash = { page ->
- // stash contains whether incoming page was empty
- page.data.isEmpty()
- },
- createInsert = { insert, _, _ ->
- if (insert.pages.any { it.data.isEmpty() }) {
- // filter out empty pages
- insert.transformPages { pages -> pages.filter { it.data.isNotEmpty() } }
- } else {
- // no empty pages, can safely reuse this page
- insert
- }
- },
- createDrop = { drop, pageStash, _ ->
- var newCount = drop.count
- if (drop.loadType == PREPEND) {
- repeat(drop.count) { i ->
- if (pageStash[i]) {
- newCount--
- }
- }
- } else {
- repeat(drop.count) { i ->
- if (pageStash[pageStash.lastIndex - i]) {
- newCount--
- }
- }
- }
- if (drop.count == newCount) {
- drop
- } else {
- drop.copy(count = newCount)
- }
- }
-)
diff --git a/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshot.kt b/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshot.kt
index 776d7ac..df615df 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshot.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshot.kt
@@ -22,7 +22,6 @@
import androidx.paging.LoadType.APPEND
import androidx.paging.LoadType.PREPEND
import androidx.paging.LoadType.REFRESH
-import androidx.paging.PageEvent.Drop
import androidx.paging.PageEvent.LoadStateUpdate
import androidx.paging.PagingSource.LoadParams
import androidx.paging.PagingSource.LoadResult
@@ -498,9 +497,9 @@
}
stateLock.withLock {
- state.dropInfo(dropType, generationalHint.hint)?.let { info ->
- state.drop(dropType, info.pageCount, info.placeholdersRemaining)
- pageEventCh.send(Drop(dropType, info.pageCount, info.placeholdersRemaining))
+ state.dropEventOrNull(dropType, generationalHint.hint)?.let { event ->
+ state.drop(event)
+ pageEventCh.send(event)
}
loadKey = state.nextLoadKeyOrNull(loadType, generationalHint, itemsLoaded)
diff --git a/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshotState.kt b/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshotState.kt
index 3a28a06..3f05e26 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshotState.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PageFetcherSnapshotState.kt
@@ -123,7 +123,7 @@
PREPEND -> 0 - initialPageIndex
APPEND -> pages.size - initialPageIndex - 1
}
- val pages = listOf(TransformablePage(sourcePageIndex, data, data.size, null))
+ val pages = listOf(TransformablePage(sourcePageIndex, data))
return when (loadType) {
REFRESH -> Refresh(
pages = pages,
@@ -197,38 +197,43 @@
return true
}
- fun drop(loadType: LoadType, pageCount: Int, placeholdersRemaining: Int) {
- check(pages.size >= pageCount) {
- "invalid drop count. have ${pages.size} but wanted to drop $pageCount"
+ fun drop(event: PageEvent.Drop<Value>) {
+ check(event.pageCount <= pages.size) {
+ "invalid drop count. have ${pages.size} but wanted to drop ${event.pageCount}"
}
// Reset load state to NotLoading(endOfPaginationReached = false).
- failedHintsByLoadType.remove(loadType)
- loadStates.set(loadType, false, NotLoading.Incomplete)
+ failedHintsByLoadType.remove(event.loadType)
+ loadStates.set(event.loadType, false, NotLoading.Incomplete)
- when (loadType) {
+ when (event.loadType) {
PREPEND -> {
- repeat(pageCount) { _pages.removeAt(0) }
- initialPageIndex -= pageCount
+ repeat(event.pageCount) { _pages.removeAt(0) }
+ initialPageIndex -= event.pageCount
- placeholdersBefore = placeholdersRemaining
+ placeholdersBefore = event.placeholdersRemaining
prependLoadId++
prependLoadIdCh.offer(prependLoadId)
}
APPEND -> {
- repeat(pageCount) { _pages.removeAt(pages.size - 1) }
+ repeat(event.pageCount) { _pages.removeAt(pages.size - 1) }
- placeholdersAfter = placeholdersRemaining
+ placeholdersAfter = event.placeholdersRemaining
appendLoadId++
appendLoadIdCh.offer(appendLoadId)
}
- else -> throw IllegalArgumentException("cannot drop $loadType")
+ else -> throw IllegalArgumentException("cannot drop ${event.loadType}")
}
}
- fun dropInfo(loadType: LoadType, hint: ViewportHint): DropInfo? {
+ /**
+ * @return [PageEvent.Drop] for [loadType] that would allow this [PageFetcherSnapshotState] to
+ * respect [PagingConfig.maxSize], `null` if no pages should be dropped for the provided
+ * [loadType].
+ */
+ fun dropEventOrNull(loadType: LoadType, hint: ViewportHint): PageEvent.Drop<Value>? {
if (config.maxSize == MAX_SIZE_UNBOUNDED) return null
// Never drop below 2 pages as this can cause UI flickering with certain configs and it's
// much more important to protect against this behaviour over respecting a config where
@@ -237,57 +242,53 @@
if (storageCount <= config.maxSize) return null
- when (loadType) {
- REFRESH -> throw IllegalArgumentException(
- "Drop LoadType must be PREPEND or APPEND, but got $loadType"
- )
- PREPEND -> {
- var pageCount = 0
- var itemsToDrop = 0
- while (pageCount < pages.size && storageCount - itemsToDrop > config.maxSize) {
- val pageSize = pages[pageCount].data.size
- val itemsAfterDrop = hint.presentedItemsBefore - itemsToDrop - pageSize
- // Do not drop pages that would fulfill prefetchDistance.
- if (itemsAfterDrop < config.prefetchDistance) break
+ require(loadType != REFRESH) {
+ "Drop LoadType must be PREPEND or APPEND, but got $loadType"
+ }
- itemsToDrop += pageSize
- pageCount++
- }
+ // Compute pageCount and itemsToDrop
+ var pagesToDrop = 0
+ var itemsToDrop = 0
+ while (pagesToDrop < pages.size && storageCount - itemsToDrop > config.maxSize) {
+ val pageSize = when (loadType) {
+ PREPEND -> pages[pagesToDrop].data.size
+ else -> pages[pages.lastIndex - pagesToDrop].data.size
+ }
+ val itemsAfterDrop = when (loadType) {
+ PREPEND -> hint.presentedItemsBefore - itemsToDrop - pageSize
+ else -> hint.presentedItemsAfter - itemsToDrop - pageSize
+ }
+ // Do not drop pages that would fulfill prefetchDistance.
+ if (itemsAfterDrop < config.prefetchDistance) break
- val placeholdersRemaining = when {
+ itemsToDrop += pageSize
+ pagesToDrop++
+ }
+
+ return when (pagesToDrop) {
+ 0 -> null
+ else -> PageEvent.Drop(
+ loadType = loadType,
+ minPageOffset = when (loadType) {
+ // originalPageOffset of the first page.
+ PREPEND -> -initialPageIndex
+ // maxPageOffset - pagesToDrop; We subtract one from pagesToDrop, since this
+ // value is inclusive.
+ else -> pages.lastIndex - initialPageIndex - (pagesToDrop - 1)
+ },
+ maxPageOffset = when (loadType) {
+ // minPageOffset + pagesToDrop; We subtract on from pagesToDrop, since this
+ // value is inclusive.
+ PREPEND -> (pagesToDrop - 1) - initialPageIndex
+ // originalPageOffset of the last page.
+ else -> pages.lastIndex - initialPageIndex
+ },
+ placeholdersRemaining = when {
!config.enablePlaceholders -> 0
- else -> placeholdersBefore + itemsToDrop
- }
-
- return when (pageCount) {
- 0 -> null
- else -> DropInfo(pageCount, placeholdersRemaining)
- }
- } APPEND -> {
- var pageCount = 0
- var itemsToDrop = 0
- while (pageCount < pages.size && storageCount - itemsToDrop > config.maxSize) {
- val pageSize = pages[pages.lastIndex - pageCount].data.size
- val itemsAfterDrop = hint.presentedItemsAfter - itemsToDrop - pageSize
- // Do not drop pages that would fulfill prefetchDistance.
- if (itemsAfterDrop < config.prefetchDistance) break
-
- itemsToDrop += pageSize
- pageCount++
- }
-
- val placeholdersRemaining = when {
- !config.enablePlaceholders -> 0
+ loadType == PREPEND -> placeholdersBefore + itemsToDrop
else -> placeholdersAfter + itemsToDrop
}
-
- return when (pageCount) {
- 0 -> null
- else -> DropInfo(pageCount, placeholdersRemaining)
- }
- }
+ )
}
}
}
-
-internal class DropInfo(val pageCount: Int, val placeholdersRemaining: Int)
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt b/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt
index 26142d3..f0e49eb 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagePresenter.kt
@@ -31,11 +31,10 @@
private val pages: MutableList<TransformablePage<T>> = insertEvent.pages.toMutableList()
override var storageCount: Int = insertEvent.pages.fullCount()
private set
-
- val firstPageIndex: Int
- get() = pages.first().originalPageOffset
- val lastPageIndex: Int
- get() = pages.last().originalPageOffset
+ private val originalPageOffsetFirst: Int
+ get() = pages.first().originalPageOffsets.min()!!
+ private val originalPageOffsetLast: Int
+ get() = pages.last().originalPageOffsets.max()!!
override var placeholdersBefore: Int = insertEvent.placeholdersBefore
private set
override var placeholdersAfter: Int = insertEvent.placeholdersAfter
@@ -107,7 +106,7 @@
}
}
- fun presenterIndexToHint(index: Int): ViewportHint {
+ fun viewportHintForPresenterIndex(index: Int): ViewportHint {
var pageIndex = 0
var indexInPage = index - placeholdersBefore
while (indexInPage >= pages[pageIndex].data.size && pageIndex < pages.lastIndex) {
@@ -116,19 +115,12 @@
pageIndex++
}
- val originalIndices = pages[pageIndex].originalIndices
- return ViewportHint(
- pageOffset = pages[pageIndex].originalPageOffset,
- indexInPage = if (originalIndices != null && indexInPage in originalIndices.indices) {
- originalIndices[indexInPage]
- } else {
- indexInPage
- },
+ return pages[pageIndex].viewportHintFor(
+ index = indexInPage,
presentedItemsBefore = index - placeholdersBefore,
presentedItemsAfter = size - index - placeholdersAfter - 1,
- originalPageOffsetFirst = firstPageIndex,
- originalPageOffsetLast = lastPageIndex
-
+ originalPageOffsetFirst = originalPageOffsetFirst,
+ originalPageOffsetLast = originalPageOffsetLast
)
}
@@ -208,33 +200,67 @@
}
}
+ /**
+ * @param pageOffsetsToDrop originalPageOffset of pages that were dropped
+ * @return The number of items dropped
+ */
+ private fun dropPagesWithOffsets(pageOffsetsToDrop: IntRange): Int {
+ var removeCount = 0
+ val pageIterator = pages.iterator()
+ while (pageIterator.hasNext()) {
+ val page = pageIterator.next()
+ if (page.originalPageOffsets.any { pageOffsetsToDrop.contains(it) }) {
+ removeCount += page.data.size
+ pageIterator.remove()
+ }
+ }
+
+ return removeCount
+ }
+
+ /**
+ * Helper which converts a [PageEvent.Drop] to a set of [ProcessPageEventCallback] events by
+ * dropping all pages that depend on the n-lowest or n-highest originalPageOffsets.
+ *
+ * Note: We never run DiffUtil here because it is safe to assume that empty pages can never
+ * become non-empty no matter what transformations they go through. [ProcessPageEventCallback]
+ * events generated by this helper always drop contiguous sets of items because pages that
+ * depend on multiple originalPageOffsets will always be the next closest page that's non-empty.
+ */
private fun dropPages(drop: PageEvent.Drop<T>, callback: ProcessPageEventCallback) {
val oldSize = size
+
if (drop.loadType == PREPEND) {
- val removeCount = pages.take(drop.count).fullCount()
-
- val placeholdersChangedCount = minOf(drop.placeholdersRemaining, removeCount)
- val placeholdersChangedPos = placeholdersBefore + removeCount -
- placeholdersChangedCount
-
- val itemsRemovedCount = removeCount - placeholdersChangedCount
- val itemsRemovedPos = 0
+ val oldPlaceholdersBefore = placeholdersBefore
// first update all state...
- for (i in 0 until drop.count) {
- pages.removeAt(0)
- }
- storageCount -= removeCount
+ val itemDropCount = dropPagesWithOffsets(drop.minPageOffset..drop.maxPageOffset)
+ storageCount -= itemDropCount
placeholdersBefore = drop.placeholdersRemaining
// ... then trigger callbacks, so callbacks won't see inconsistent state
- callback.onChanged(placeholdersChangedPos, placeholdersChangedCount)
- callback.onRemoved(itemsRemovedPos, itemsRemovedCount)
- val placeholderInsertedCount = size - oldSize + itemsRemovedCount
- if (placeholderInsertedCount > 0) {
- callback.onInserted(0, placeholderInsertedCount)
- } else if (placeholderInsertedCount < 0) {
- callback.onRemoved(0, -placeholderInsertedCount)
+ // Trim or insert to expected size.
+ val expectedSize = size
+ val placeholdersToInsert = expectedSize - oldSize
+ if (placeholdersToInsert > 0) {
+ callback.onInserted(0, placeholdersToInsert)
+ } else if (placeholdersToInsert < 0) {
+ callback.onRemoved(0, -placeholdersToInsert)
+ }
+
+ // Compute the index of the first item that must be rebound as a placeholder.
+ // If any placeholders were inserted above, we only need to send onChanged for the next
+ // n = (drop.placeholdersRemaining - placeholdersToInsert) items. E.g., if two nulls
+ // were inserted above, then the onChanged event can start from index = 2.
+ // Note: In cases where more items were dropped than there were previously placeholders,
+ // we can simply rebind n = drop.placeholdersRemaining items starting from position = 0.
+ val firstItemIndex = maxOf(0, oldPlaceholdersBefore + placeholdersToInsert)
+ // Compute the number of previously loaded items that were dropped and now need to be
+ // updated to null. This computes the distance between firstItemIndex (inclusive),
+ // and index of the last leading placeholder (inclusive) in the final list.
+ val changeCount = drop.placeholdersRemaining - firstItemIndex
+ if (changeCount > 0) {
+ callback.onChanged(firstItemIndex, changeCount)
}
// Dropping from prepend direction implies NotLoading(endOfPaginationReached = false).
@@ -244,29 +270,40 @@
loadState = NotLoading.Incomplete
)
} else {
- val removeCount = pages.takeLast(drop.count).fullCount()
-
- val placeholdersChangedCount = minOf(drop.placeholdersRemaining, removeCount)
- val placeholdersChangedPos = placeholdersBefore + storageCount - removeCount
-
- val itemsRemovedCount = removeCount - placeholdersChangedCount
- val itemsRemovedPos = placeholdersChangedPos + placeholdersChangedCount
+ val oldPlaceholdersAfter = placeholdersAfter
// first update all state...
- for (i in 0 until drop.count) {
- pages.removeAt(pages.lastIndex)
- }
- storageCount -= removeCount
+ val itemDropCount = dropPagesWithOffsets(drop.minPageOffset..drop.maxPageOffset)
+ storageCount -= itemDropCount
placeholdersAfter = drop.placeholdersRemaining
// ... then trigger callbacks, so callbacks won't see inconsistent state
- callback.onChanged(placeholdersChangedPos, placeholdersChangedCount)
- callback.onRemoved(itemsRemovedPos, itemsRemovedCount)
- val placeholderInsertedCount = size - oldSize + itemsRemovedCount
- if (placeholderInsertedCount > 0) {
- callback.onInserted(size, placeholderInsertedCount)
- } else if (placeholderInsertedCount < 0) {
- callback.onRemoved(size, -placeholderInsertedCount)
+ // Trim or insert to expected size.
+ val expectedSize = size
+ val placeholdersToInsert = expectedSize - oldSize
+ if (placeholdersToInsert > 0) {
+ callback.onInserted(oldSize, placeholdersToInsert)
+ } else if (placeholdersToInsert < 0) {
+ callback.onRemoved(oldSize + placeholdersToInsert, -placeholdersToInsert)
+ }
+
+ // Number of trailing placeholders in the list, before dropping, that were removed
+ // above during size adjustment.
+ val oldPlaceholdersRemoved = when {
+ placeholdersToInsert < 0 -> minOf(oldPlaceholdersAfter, -placeholdersToInsert)
+ else -> 0
+ }
+ // Compute the number of previously loaded items that were dropped and now need to be
+ // updated to null. This subtracts the total number of existing placeholders in the
+ // list, before dropping, that were not removed above during size adjustment, from
+ // the total number of expected placeholders.
+ val changeCount =
+ drop.placeholdersRemaining - (oldPlaceholdersAfter - oldPlaceholdersRemoved)
+ if (changeCount > 0) {
+ callback.onChanged(
+ position = size - drop.placeholdersRemaining,
+ count = changeCount
+ )
}
// Dropping from append direction implies NotLoading(endOfPaginationReached = false).
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagingDataDiffer.kt b/paging/common/src/main/kotlin/androidx/paging/PagingDataDiffer.kt
index 975bd64..746fefc 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagingDataDiffer.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagingDataDiffer.kt
@@ -121,6 +121,8 @@
suspend fun collectFrom(pagingData: PagingData<T>) = collectFromRunner.runInIsolation {
receiver = pagingData.receiver
+ // TODO: Validate only empty pages between separator pages and its dependent
+ // pages.
pagingData.flow.collect { event ->
withContext<Unit>(mainDispatcher) {
if (event is PageEvent.Insert && event.loadType == REFRESH) {
@@ -151,7 +153,9 @@
// list.
transformedLastAccessedIndex?.let { newIndex ->
lastAccessedIndex = newIndex
- receiver?.accessHint(newPresenter.presenterIndexToHint(newIndex))
+ receiver?.accessHint(
+ newPresenter.viewportHintForPresenterIndex(newIndex)
+ )
}
} else {
if (postEvents()) {
@@ -170,7 +174,8 @@
// If index points to a placeholder after transformations, resend it unless
// there are no more items to load.
if (event is PageEvent.Insert) {
- val prependDone = event.combinedLoadStates.prepend.endOfPaginationReached
+ val prependDone =
+ event.combinedLoadStates.prepend.endOfPaginationReached
val appendDone = event.combinedLoadStates.append.endOfPaginationReached
val canContinueLoading = !(event.loadType == PREPEND && prependDone) &&
!(event.loadType == APPEND && appendDone)
@@ -187,7 +192,7 @@
if (shouldResendHint) {
receiver?.accessHint(
- presenter.presenterIndexToHint(lastAccessedIndex)
+ presenter.viewportHintForPresenterIndex(lastAccessedIndex)
)
} else {
// lastIndex fulfilled, so reset lastAccessedIndexUnfulfilled.
@@ -211,7 +216,7 @@
lastAccessedIndexUnfulfilled = true
lastAccessedIndex = index
- receiver?.accessHint(presenter.presenterIndexToHint(index))
+ receiver?.accessHint(presenter.viewportHintForPresenterIndex(index))
return presenter.get(index)
}
diff --git a/paging/common/src/main/kotlin/androidx/paging/Separators.kt b/paging/common/src/main/kotlin/androidx/paging/Separators.kt
index 5dda66d..5154f5b 100644
--- a/paging/common/src/main/kotlin/androidx/paging/Separators.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/Separators.kt
@@ -41,7 +41,7 @@
val outputIndices = ArrayList<Int>(initialCapacity)
outputList.add(data.first())
- outputIndices.add(originalIndices?.first() ?: 0)
+ outputIndices.add(hintOriginalIndices?.first() ?: 0)
for (i in 1 until data.size) {
val item = data[i]
val separator = generator(data[i - 1], item)
@@ -63,138 +63,100 @@
this as TransformablePage<R>
} else {
TransformablePage(
- originalPageOffset = originalPageOffset,
+ originalPageOffsets = originalPageOffsets,
data = outputList,
- originalPageSize = originalPageSize,
- originalIndices = outputIndices
+ hintOriginalPageOffset = hintOriginalPageOffset,
+ hintOriginalIndices = outputIndices
)
}
}
/**
- * Create a TransformablePage with the given separator (or empty, if the separator is null)
+ * Create a [TransformablePage] with the given separator (or empty, if the separator is null)
*/
internal fun <T : Any> separatorPage(
+ separator: T,
+ originalPageOffsets: IntArray,
+ hintOriginalPageOffset: Int,
+ hintOriginalIndex: Int
+): TransformablePage<T> = TransformablePage(
+ originalPageOffsets = originalPageOffsets,
+ data = listOf(separator),
+ hintOriginalPageOffset = hintOriginalPageOffset,
+ hintOriginalIndices = listOf(hintOriginalIndex)
+)
+
+/**
+ * Create a [TransformablePage] with the given separator, and add it if [separator] is non-null
+ *
+ * This is a helper to create separator pages that contain a single separator to be used to join
+ * pages provided from stream.
+ */
+internal fun <T : Any> MutableList<TransformablePage<T>>.addSeparatorPage(
separator: T?,
- originalPageOffset: Int,
- originalPageSize: Int,
- originalIndex: Int
-): TransformablePage<T> = if (separator != null) {
- // page with just the separator
- TransformablePage(
- originalPageOffset = originalPageOffset,
- data = listOf(separator),
- originalPageSize = originalPageSize,
- originalIndices = listOf(originalIndex)
- )
-} else {
- // empty page
- TransformablePage(
- originalPageOffset = originalPageOffset,
- data = emptyList(),
- originalPageSize = originalPageSize,
- originalIndices = null
- )
-}
-
-/**
- * Create a TransformablePage with the given separator (or empty, if the separator is null)
- */
-internal fun <R : Any, T : R> separatorPage(
- separator: R?,
- adjacentPage: TransformablePage<T>,
- originalIndex: Int
-): TransformablePage<R> = separatorPage(
- separator = separator,
- originalPageOffset = adjacentPage.originalPageOffset,
- originalPageSize = adjacentPage.originalPageSize,
- originalIndex = originalIndex
-)
-
-/**
- * Create a TransformablePage with the given separator (or empty, if the separator is null)
- */
-internal fun <R : Any, T : R> separatorPage(
- separator: R?,
- adjacentPage: DataPage<T>,
- originalIndex: Int
-): TransformablePage<R> = separatorPage(
- separator = separator,
- originalPageOffset = adjacentPage.originalPageOffset,
- originalPageSize = adjacentPage.originalPageSize,
- originalIndex = originalIndex
-)
-
-/**
- * Per-page adjacency info - used to create adjacent separators.
- */
-internal class DataPage<T : Any>(
- page: TransformablePage<T>
+ originalPageOffsets: IntArray,
+ hintOriginalPageOffset: Int,
+ hintOriginalIndex: Int
) {
- val first: T = page.data.first()
- val last: T = page.data.last()
- val originalPageOffset: Int = page.originalPageOffset
- val originalPageSize: Int = page.originalPageSize
- val originalLastIndex
- get() = originalPageSize - 1
+ if (separator == null) return
+
+ val separatorPage = separatorPage(
+ separator = separator,
+ originalPageOffsets = originalPageOffsets,
+ hintOriginalPageOffset = hintOriginalPageOffset,
+ hintOriginalIndex = hintOriginalIndex
+ )
+ add(separatorPage)
}
/**
- * Iterate through the list of page info, dropping events, and mapping the incoming drop count to
- * an output count.
+ * Create a [TransformablePage] with the given separator, and add it if [separator] is non-null
+ *
+ * This is a helper to create separator pages that contain a single separator to be used to join
+ * pages provided from stream.
*/
-private inline fun <T : Any> MutableList<DataPage<T>?>.dropPages(
- nonSeparatorCount: Int,
- indexProvider: (List<DataPage<T>?>) -> Int
-): Int {
- if (isEmpty()) {
- // nothing to drop
- check(nonSeparatorCount == 0)
- return 0
- }
-
- // drop nonSeparatorCount of pages. Even if 0, we want to be sure to drop a terminal
- // separator, since that side of the list is no longer done
- var nonSeparatorPagesToDrop = nonSeparatorCount
- var outputDropCount = 0
- while (nonSeparatorPagesToDrop > 0) {
- val page = removeAt(indexProvider(this))
- if (page != null) {
- nonSeparatorPagesToDrop--
- }
- outputDropCount++
- }
-
- // now check if last page is a separator. if so, we need to drop it too, since it was built
- // with now-dropped data (unless nonSeparatorCount was 0, which is why the early return)
- val finalPotentialSeparatorIndex = indexProvider(this)
- val finalPage = get(finalPotentialSeparatorIndex)
- if (finalPage == null) {
- removeAt(finalPotentialSeparatorIndex)
- outputDropCount++
- }
- return outputDropCount
+internal fun <R : Any, T : R> MutableList<TransformablePage<R>>.addSeparatorPage(
+ separator: R?,
+ adjacentPageBefore: TransformablePage<T>?,
+ adjacentPageAfter: TransformablePage<T>?,
+ hintOriginalPageOffset: Int,
+ hintOriginalIndex: Int
+) {
+ val beforeOffsets = adjacentPageBefore?.originalPageOffsets
+ val afterOffsets = adjacentPageAfter?.originalPageOffsets
+ addSeparatorPage(
+ separator = separator,
+ originalPageOffsets = when {
+ beforeOffsets != null && afterOffsets != null -> {
+ (beforeOffsets + afterOffsets).distinct().sorted().toIntArray()
+ }
+ beforeOffsets == null && afterOffsets != null -> afterOffsets
+ beforeOffsets != null && afterOffsets == null -> beforeOffsets
+ else -> throw IllegalArgumentException(
+ "Separator page expected adjacentPageBefore or adjacentPageAfter, but both were" +
+ " null."
+ )
+ },
+ hintOriginalPageOffset = hintOriginalPageOffset,
+ hintOriginalIndex = hintOriginalIndex
+ )
}
-internal fun <T : Any> MutableList<DataPage<T>?>.dropPagesStart(count: Int): Int =
- dropPages(count) { 0 }
-
-internal fun <T : Any> MutableList<DataPage<T>?>.dropPagesEnd(count: Int): Int =
- dropPages(count) { it.lastIndex }
-
private class SeparatorState<R : Any, T : R>(
- val generator: suspend (T?, T?) -> R?
+ val generator: suspend (before: T?, after: T?) -> R?
) {
/**
- * Lookup table of previously emitted pages.
+ * Lookup table of previously emitted pages, that skips empty pages.
*
- * Separator -> null
- * Non-separator -> DataPage
+ * This table is used to keep track of originalPageOffsets for separators that would span
+ * across empty pages. It includes a simplified version of loaded pages which only has the
+ * first and last item in each page to reduce memory pressure.
*
- * This table is used to emit drops (so we know how much to pad drops to account for separators)
- * and to provide adjacency data, to insert separators as new pages arrive.
+ * Note: [TransformablePage] added to this stash must always have
+ * [TransformablePage.originalPageOffsets] defined, since it needs to keep track of the
+ * originalPageOffset of the last item.
*/
- val pageStash = mutableListOf<DataPage<T>?>()
+ val pageStash = mutableListOf<TransformablePage<T>>()
/**
* True if next insert event should be treated as terminal, as a previous terminal event was
@@ -203,10 +165,16 @@
var endTerminalSeparatorDeferred = false
var startTerminalSeparatorDeferred = false
+ var footerAdded = false
+ var headerAdded = false
+
@Suppress("UNCHECKED_CAST")
suspend fun onEvent(event: PageEvent<T>): PageEvent<R> = when (event) {
is Insert<T> -> onInsert(event)
- is Drop -> onDrop(event) as Drop<R>
+ is Drop -> {
+ onDrop(event) // Update pageStash state
+ event as Drop<R>
+ }
is PageEvent.LoadStateUpdate -> event as PageEvent<R>
}.also {
// validate internal state after each modification
@@ -248,15 +216,13 @@
suspend fun onInsert(event: Insert<T>): Insert<R> {
val eventTerminatesStart = event.terminatesStart()
val eventTerminatesEnd = event.terminatesEnd()
- val eventEmpty = event.pages.isEmpty()
+ val eventEmpty = event.pages.all { it.data.isEmpty() }
- if (pageStash.isNotEmpty()) {
- require(pageStash.first() != null || event.loadType != PREPEND) {
- "Additional prepend event after prepend state is done"
- }
- require(pageStash.last() != null || event.loadType != APPEND) {
- "Additional append event after append state is done"
- }
+ require(!headerAdded || event.loadType != PREPEND) {
+ "Additional prepend event after prepend state is done"
+ }
+ require(!footerAdded || event.loadType != APPEND) {
+ "Additional append event after append state is done"
}
if (eventEmpty) {
@@ -265,8 +231,13 @@
val separator = generator(null, null)
endTerminalSeparatorDeferred = false
startTerminalSeparatorDeferred = false
- pageStash.add(null) // represents separator
- return event.transformPages { listOf(separatorPage(separator, 0, 0, 0)) }
+ return if (separator == null) {
+ event.asRType()
+ } else {
+ event.transformPages {
+ listOf(separatorPage(separator, intArrayOf(0), 0, 0))
+ }
+ }
} else if (!eventTerminatesStart && !eventTerminatesEnd) {
// If event is non terminal simply ignore it.
return event.asRType()
@@ -285,95 +256,187 @@
// If we've gotten to this point, that means the outgoing insert will have data.
// Either this event has data, or the pageStash does.
val outList = ArrayList<TransformablePage<R>>(event.pages.size)
- val outStateList = ArrayList<DataPage<T>?>(event.pages.size)
- if (eventTerminatesStart) {
- outStateList.add(null) // represents separator
- if (eventEmpty) {
- // header separator, using data from previous generation
- val firstStash = pageStash.first()!!
- val separator = generator(null, firstStash.first)
- outList.add(separatorPage(separator, firstStash, originalIndex = 0))
- } else {
- val firstPage = event.pages.first()
- val separator = generator(null, firstPage.data.first())
- outList.add(separatorPage(separator, firstPage, originalIndex = 0))
+ val stashOutList = ArrayList<TransformablePage<T>>(event.pages.size)
+
+ var firstNonEmptyPage: TransformablePage<T>? = null
+ var firstNonEmptyPageIndex: Int? = null
+ var lastNonEmptyPage: TransformablePage<T>? = null
+ var lastNonEmptyPageIndex: Int? = null
+ if (!eventEmpty) {
+ // Compute the first non-empty page index to be used as adjacent pages for creating
+ // separator pages.
+ // Note: We're guaranteed to have at least one non-empty page at this point.
+ var pageIndex = 0
+ while (pageIndex < event.pages.lastIndex && event.pages[pageIndex].data.isEmpty()) {
+ pageIndex++
}
+ firstNonEmptyPageIndex = pageIndex
+ firstNonEmptyPage = event.pages[pageIndex]
+
+ // Compute the last non-empty page index to be used as adjacent pages for creating separator
+ // pages.
+ // Note: We're guaranteed to have at least one non-empty page at this point.
+ pageIndex = event.pages.lastIndex
+ while (pageIndex > 0 && event.pages[pageIndex].data.isEmpty()) {
+ pageIndex--
+ }
+ lastNonEmptyPageIndex = pageIndex
+ lastNonEmptyPage = event.pages[pageIndex]
}
- // create pages based on data in the event
+ // Header separator
+ if (eventTerminatesStart) {
+ headerAdded = true
+
+ // Using data from previous generation if event is empty, adjacent page otherwise.
+ val pageAfter = if (eventEmpty) pageStash.first() else firstNonEmptyPage!!
+ outList.addSeparatorPage(
+ separator = generator(null, pageAfter.data.first()),
+ adjacentPageBefore = null,
+ adjacentPageAfter = pageAfter,
+ hintOriginalPageOffset = pageAfter.hintOriginalPageOffset,
+ hintOriginalIndex = pageAfter.hintOriginalIndices?.first() ?: 0
+ )
+ }
+
+ // Create pages based on data in the event
if (!eventEmpty) {
- var itemBefore = if (event.loadType == APPEND) pageStash.lastOrNull()?.last else null
- event.pages.forEachIndexed { index, page ->
- // If page is being appended, or if we're in between pages, insert separator page
- if (index != 0 || (event.loadType == APPEND && pageStash.isNotEmpty())) {
- val separator = generator(itemBefore!!, page.data.first())
- outStateList.add(null) // represents separator
- outList.add(separatorPage(separator, page, originalIndex = 0))
+ // Add empty pages before [firstNonEmptyPageIndex] from event directly.
+ for (pageIndex in 0 until firstNonEmptyPageIndex!!) {
+ outList.add(event.pages[pageIndex].insertInternalSeparators(generator))
+ }
+
+ // Insert separator page between last stash and first non-empty event page if APPEND.
+ if (event.loadType == APPEND && pageStash.isNotEmpty()) {
+ val lastStash = pageStash.last()
+ val separator = generator(lastStash.data.last(), firstNonEmptyPage!!.data.first())
+ outList.addSeparatorPage(
+ separator = separator,
+ adjacentPageBefore = lastStash,
+ adjacentPageAfter = firstNonEmptyPage,
+ hintOriginalPageOffset = firstNonEmptyPage.hintOriginalPageOffset,
+ hintOriginalIndex = firstNonEmptyPage.hintOriginalIndices?.first() ?: 0
+ )
+ }
+
+ // Add the first non-empty insert event page with separators inserted.
+ stashOutList.add(transformablePageToStash(firstNonEmptyPage!!))
+ outList.add(firstNonEmptyPage.insertInternalSeparators(generator))
+
+ // Handle event pages that may be sparsely populated by empty pages.
+ event.pages
+ .subList(firstNonEmptyPageIndex, lastNonEmptyPageIndex!! + 1)
+ // Note: If we enter reduce loop, pageBefore is guaranteed to be non-null.
+ .reduce { pageBefore, page ->
+ if (page.data.isNotEmpty()) {
+ // Insert separator pages in between insert event pages.
+ val separator = generator(pageBefore.data.last(), page.data.first())
+ outList.addSeparatorPage(
+ separator = separator,
+ adjacentPageBefore = pageBefore,
+ adjacentPageAfter = page,
+ hintOriginalPageOffset = if (event.loadType == PREPEND) {
+ pageBefore.hintOriginalPageOffset
+ } else {
+ page.hintOriginalPageOffset
+ },
+ hintOriginalIndex = if (event.loadType == PREPEND) {
+ pageBefore.hintOriginalIndices?.last() ?: pageBefore.data.lastIndex
+ } else {
+ page.hintOriginalIndices?.first() ?: 0
+ }
+ )
+ }
+
+ if (page.data.isNotEmpty()) {
+ stashOutList.add(transformablePageToStash(page))
+ }
+ // Add the insert event page with separators inserted.
+ outList.add(page.insertInternalSeparators(generator))
+
+ // Current page becomes the next pageBefore on next iteration unless empty.
+ if (page.data.isNotEmpty()) page else pageBefore
}
- outStateList.add(DataPage(page))
- outList.add(page.insertInternalSeparators(generator))
-
- itemBefore = page.data.last()
- }
+ // Insert separator page between first stash and last non-empty event page if PREPEND.
if (event.loadType == PREPEND && pageStash.isNotEmpty()) {
- val lastPage = event.pages.last()
- val separator = generator(lastPage.data.last(), pageStash.first()!!.first)
- outStateList.add(null) // represents separator
- outList.add(
- separatorPage(separator, lastPage, lastPage.originalLastIndex)
+ val pageAfter = pageStash.first()
+ val separator = generator(lastNonEmptyPage!!.data.last(), pageAfter.data.first())
+ outList.addSeparatorPage(
+ separator = separator,
+ adjacentPageBefore = lastNonEmptyPage,
+ adjacentPageAfter = pageAfter,
+ hintOriginalPageOffset = lastNonEmptyPage.hintOriginalPageOffset,
+ hintOriginalIndex = lastNonEmptyPage.hintOriginalIndices?.last()
+ ?: lastNonEmptyPage.data.lastIndex
)
}
+
+ // Add empty pages after [lastNonEmptyPageIndex] from event directly.
+ for (pageIndex in (lastNonEmptyPageIndex + 1)..event.pages.lastIndex) {
+ outList.add(event.pages[pageIndex].insertInternalSeparators(generator))
+ }
}
+ // Footer separator
if (eventTerminatesEnd) {
- outStateList.add(null) // represents separator
- if (eventEmpty) {
- val lastStash = pageStash.last()!!
- // header separator, using data from previous generation
- val separator = generator(lastStash.last, null)
- outList.add(separatorPage(separator, lastStash, lastStash.originalLastIndex))
- } else {
- // header separator, using data from adjacent page
- val lastPage = event.pages.last()
- val separator = generator(lastPage.data.first(), null)
- outList.add(
- separatorPage(separator, lastPage, lastPage.originalLastIndex)
- )
- }
+ footerAdded = true
+
+ // Using data from previous generation if event is empty, adjacent page otherwise.
+ val pageBefore = if (eventEmpty) pageStash.last() else lastNonEmptyPage!!
+ outList.addSeparatorPage(
+ separator = generator(pageBefore.data.last(), null),
+ adjacentPageBefore = pageBefore,
+ adjacentPageAfter = null,
+ hintOriginalPageOffset = pageBefore.hintOriginalPageOffset,
+ hintOriginalIndex = pageBefore.hintOriginalIndices?.last()
+ ?: pageBefore.data.lastIndex
+ )
}
endTerminalSeparatorDeferred = false
startTerminalSeparatorDeferred = false
if (event.loadType == APPEND) {
- pageStash.addAll(outStateList)
+ pageStash.addAll(stashOutList)
} else {
- pageStash.addAll(0, outStateList)
+ pageStash.addAll(0, stashOutList)
}
return event.transformPages { outList }
}
- fun onDrop(event: Drop<T>): Drop<T> {
- val newCount = if (event.loadType == PREPEND) {
- if (pageStash.isEmpty()) {
+ /**
+ * Process a [Drop] event to update [pageStash] stage.
+ */
+ fun onDrop(event: Drop<T>) {
+ if (pageStash.isEmpty()) {
+ if (event.loadType == PREPEND) {
startTerminalSeparatorDeferred = false
- }
- pageStash.dropPagesStart(event.count)
- } else {
- if (pageStash.isEmpty()) {
+ } else {
endTerminalSeparatorDeferred = false
}
- pageStash.dropPagesEnd(event.count)
}
- @Suppress("UNCHECKED_CAST")
- return if (newCount == event.count) {
- event
- } else {
- event.copy(count = newCount)
+ // Drop all stashes that depend on pageOffset being dropped.
+ val pageOffsetsToDrop = event.minPageOffset..event.maxPageOffset
+ pageStash.removeAll { stash ->
+ stash.originalPageOffsets.any { pageOffsetsToDrop.contains(it) }
}
}
+
+ private fun <T : Any> transformablePageToStash(
+ originalPage: TransformablePage<T>
+ ): TransformablePage<T> {
+ return TransformablePage(
+ originalPageOffsets = originalPage.originalPageOffsets,
+ data = listOf(originalPage.data.first(), originalPage.data.last()),
+ hintOriginalPageOffset = originalPage.hintOriginalPageOffset,
+ hintOriginalIndices = listOf(
+ originalPage.hintOriginalIndices?.first() ?: 0,
+ originalPage.hintOriginalIndices?.last() ?: originalPage.data.lastIndex
+ )
+ )
+ }
}
/**
@@ -384,5 +447,5 @@
generator: suspend (T?, T?) -> R?
): Flow<PageEvent<R>> {
val separatorState = SeparatorState { before: T?, after: T? -> generator(before, after) }
- return removeEmptyPages().map { separatorState.onEvent(it) }
+ return map { separatorState.onEvent(it) }
}
\ No newline at end of file
diff --git a/paging/common/src/main/kotlin/androidx/paging/TransformablePage.kt b/paging/common/src/main/kotlin/androidx/paging/TransformablePage.kt
index f091909..a4e378c 100644
--- a/paging/common/src/main/kotlin/androidx/paging/TransformablePage.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/TransformablePage.kt
@@ -18,9 +18,12 @@
internal data class TransformablePage<T : Any>(
/**
- * Index of the original page (pre-transformation) relative to initial load = 0
+ * List of original (pre-transformation) page offsets the original page relative to initial = 0,
+ * that this [TransformablePage] depends on.
+ *
+ * This array is always sorted.
*/
- val originalPageOffset: Int,
+ val originalPageOffsets: IntArray,
/**
* Data to present (post-transformation)
@@ -28,9 +31,10 @@
val data: List<T>,
/**
- * Size of the original page (pre-transformation)
+ * Original (pre-transformation) page offset relative to initial = 0, that [hintOriginalIndices]
+ * are associated with.
*/
- val originalPageSize: Int,
+ val hintOriginalPageOffset: Int,
/**
* Optional lookup table for page indices.
@@ -39,24 +43,73 @@
* pre-transformation index.
*
* If null, the indices of [data] map directly to their original pre-transformation index.
+ *
+ * Note: [hintOriginalIndices] refers to indices of the original item which can be found in the
+ * loaded pages with pageOffset == [hintOriginalPageOffset].
*/
- val originalIndices: List<Int>?
+ val hintOriginalIndices: List<Int>?
) {
/**
* Simple constructor for creating pre-transformation pages, which don't need an index lookup
+ * and only reference a single [originalPageOffset].
*/
constructor(
originalPageOffset: Int,
data: List<T>
- ) : this(originalPageOffset, data, data.size, null)
+ ) : this(intArrayOf(originalPageOffset), data, originalPageOffset, null)
init {
- require(originalIndices == null || originalIndices.size == data.size) {
- "If originalIndices (size = ${originalIndices!!.size}) is provided," +
+ require(originalPageOffsets.isNotEmpty()) {
+ "originalPageOffsets cannot be empty when constructing TransformablePage"
+ }
+
+ require(hintOriginalIndices == null || hintOriginalIndices.size == data.size) {
+ "If originalIndices (size = ${hintOriginalIndices!!.size}) is provided," +
" it must be same length as data (size = ${data.size})"
}
}
- val originalLastIndex
- get() = originalPageSize - 1
+ fun viewportHintFor(
+ index: Int,
+ presentedItemsBefore: Int,
+ presentedItemsAfter: Int,
+ originalPageOffsetFirst: Int,
+ originalPageOffsetLast: Int
+ ) = ViewportHint(
+ pageOffset = hintOriginalPageOffset,
+ indexInPage = when {
+ hintOriginalIndices?.indices?.contains(index) == true -> hintOriginalIndices[index]
+ else -> index
+ },
+ presentedItemsBefore = presentedItemsBefore,
+ presentedItemsAfter = presentedItemsAfter,
+ originalPageOffsetFirst = originalPageOffsetFirst,
+ originalPageOffsetLast = originalPageOffsetLast
+ )
+
+ // Do not edit. Implementation generated by Studio, since data class uses referential equality
+ // for IntArray.
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as TransformablePage<*>
+
+ if (!originalPageOffsets.contentEquals(other.originalPageOffsets)) return false
+ if (data != other.data) return false
+ if (hintOriginalPageOffset != other.hintOriginalPageOffset) return false
+ if (hintOriginalIndices != other.hintOriginalIndices) return false
+
+ return true
+ }
+
+ // Do not edit. Implementation generated by Studio, since data class uses referential equality
+ // for IntArray.
+ override fun hashCode(): Int {
+ var result = originalPageOffsets.contentHashCode()
+ result = 31 * result + data.hashCode()
+ result = 31 * result + hintOriginalPageOffset
+ result = 31 * result + (hintOriginalIndices?.hashCode() ?: 0)
+ return result
+ }
}
diff --git a/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt b/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt
index 0ad5c801..39223c1 100644
--- a/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/CachingTest.kt
@@ -325,8 +325,8 @@
indexInPage = it.pages.last().data.size - 1,
presentedItemsBefore = 0,
presentedItemsAfter = 0,
- originalPageOffsetFirst = it.pages.first().originalPageOffset,
- originalPageOffsetLast = it.pages.last().originalPageOffset
+ originalPageOffsetFirst = it.pages.first().originalPageOffsets.min()!!,
+ originalPageOffsetLast = it.pages.last().originalPageOffsets.max()!!
)
)
} else {
diff --git a/paging/common/src/test/kotlin/androidx/paging/FlattenedPageEventStorageTest.kt b/paging/common/src/test/kotlin/androidx/paging/FlattenedPageEventStorageTest.kt
index f088e92..99d2f91 100644
--- a/paging/common/src/test/kotlin/androidx/paging/FlattenedPageEventStorageTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/FlattenedPageEventStorageTest.kt
@@ -176,7 +176,8 @@
list.add(
Drop(
loadType = PREPEND,
- count = 1,
+ minPageOffset = 0,
+ maxPageOffset = 0,
placeholdersRemaining = 6
)
)
@@ -212,7 +213,8 @@
list.add(
Drop(
loadType = APPEND,
- count = 1,
+ minPageOffset = 1,
+ maxPageOffset = 1,
placeholdersRemaining = 7
)
)
diff --git a/paging/common/src/test/kotlin/androidx/paging/HeaderFooterTest.kt b/paging/common/src/test/kotlin/androidx/paging/HeaderFooterTest.kt
index 7aa8693..85bac00 100644
--- a/paging/common/src/test/kotlin/androidx/paging/HeaderFooterTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/HeaderFooterTest.kt
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-@file:OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
-
package androidx.paging
import androidx.paging.LoadState.NotLoading
import androidx.paging.PageEvent.Insert.Companion.Append
import androidx.paging.PageEvent.Insert.Companion.Prepend
import androidx.paging.PageEvent.Insert.Companion.Refresh
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.single
import kotlinx.coroutines.test.runBlockingTest
@@ -38,6 +38,7 @@
appendLocal = NotLoading.Complete
)
+@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(JUnit4::class)
class HeaderFooterTest {
@@ -62,9 +63,7 @@
pages = listOf(
TransformablePage(
data = listOf(0),
- originalPageOffset = -1,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffset = -1
)
),
placeholdersBefore = 0,
@@ -75,22 +74,20 @@
pages = listOf(
TransformablePage(
data = listOf(-1),
- originalPageOffset = -1,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffsets = intArrayOf(-1),
+ hintOriginalPageOffset = -1,
+ hintOriginalIndices = listOf(0)
),
TransformablePage(
data = listOf(0),
- originalPageOffset = -1,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffset = -1
)
),
placeholdersBefore = 0,
combinedLoadStates = fullLoadStates
)
- assertEquals(expected, actual)
+ assertThat(actual).isEqualTo(expected)
}
@Test
@@ -99,9 +96,7 @@
pages = listOf(
TransformablePage(
data = listOf("a"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffset = 0
)
),
placeholdersBefore = 0,
@@ -113,21 +108,13 @@
pages = listOf(
TransformablePage(
data = listOf("HEADER"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffsets = intArrayOf(0),
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0)
),
TransformablePage(
data = listOf("a"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
- ),
- TransformablePage(
- data = listOf(),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = null
+ originalPageOffset = 0
)
),
placeholdersBefore = 0,
@@ -135,7 +122,7 @@
combinedLoadStates = fullLoadStates
)
- assertEquals(expected, actual)
+ assertThat(actual).isEqualTo(expected)
}
@Test
@@ -144,9 +131,7 @@
pages = listOf(
TransformablePage(
data = emptyList<String>(),
- originalPageOffset = 0,
- originalPageSize = 0,
- originalIndices = emptyList()
+ originalPageOffset = 0
)
),
placeholdersBefore = 0,
@@ -158,9 +143,9 @@
pages = listOf(
TransformablePage(
data = listOf("HEADER"),
- originalPageOffset = 0,
- originalPageSize = 0,
- originalIndices = listOf(0)
+ originalPageOffsets = intArrayOf(0),
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0)
)
),
placeholdersBefore = 0,
@@ -177,9 +162,7 @@
pages = listOf(
TransformablePage(
data = listOf("b"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffset = 0
)
),
placeholdersAfter = 0,
@@ -190,15 +173,13 @@
pages = listOf(
TransformablePage(
data = listOf("b"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffset = 0
),
TransformablePage(
data = listOf("FOOTER"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffsets = intArrayOf(0),
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0)
)
),
placeholdersAfter = 0,
@@ -214,9 +195,7 @@
pages = listOf(
TransformablePage(
data = listOf("a"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffset = 0
)
),
placeholdersBefore = 0,
@@ -227,22 +206,14 @@
val expected = Refresh(
pages = listOf(
TransformablePage(
- data = listOf(),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = null
- ),
- TransformablePage(
data = listOf("a"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffset = 0
),
TransformablePage(
data = listOf("FOOTER"),
- originalPageOffset = 0,
- originalPageSize = 1,
- originalIndices = listOf(0)
+ originalPageOffsets = intArrayOf(0),
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0)
)
),
placeholdersBefore = 0,
@@ -250,7 +221,7 @@
combinedLoadStates = fullLoadStates
)
- assertEquals(expected, actual)
+ assertThat(actual).isEqualTo(expected)
}
@Test
@@ -259,9 +230,7 @@
pages = listOf(
TransformablePage(
data = emptyList<String>(),
- originalPageOffset = 0,
- originalPageSize = 0,
- originalIndices = emptyList()
+ originalPageOffset = 0
)
),
placeholdersBefore = 0,
@@ -273,9 +242,9 @@
pages = listOf(
TransformablePage(
data = listOf("FOOTER"),
- originalPageOffset = 0,
- originalPageSize = 0,
- originalIndices = listOf(0)
+ originalPageOffsets = intArrayOf(0),
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0)
)
),
placeholdersBefore = 0,
@@ -283,6 +252,6 @@
combinedLoadStates = fullLoadStates
)
- assertEquals(expected, actual)
+ assertThat(actual).isEqualTo(expected)
}
}
\ No newline at end of file
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageEventTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageEventTest.kt
index 5aec5b3..88d0583 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageEventTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageEventTest.kt
@@ -89,18 +89,20 @@
assertFailsWith<IllegalArgumentException> {
Drop<Char>(
loadType = REFRESH,
- count = 2,
+ minPageOffset = 0,
+ maxPageOffset = 0,
placeholdersRemaining = 4
)
}
}
@Test
- fun dropCount() {
+ fun dropRange() {
assertFailsWith<IllegalArgumentException> {
Drop<Char>(
loadType = REFRESH,
- count = -1,
+ minPageOffset = 2,
+ maxPageOffset = 0,
placeholdersRemaining = 4
)
}
@@ -111,7 +113,8 @@
assertFailsWith<IllegalArgumentException> {
Drop<Char>(
loadType = REFRESH,
- count = 1,
+ minPageOffset = 0,
+ maxPageOffset = 0,
placeholdersRemaining = -1
)
}
@@ -121,7 +124,8 @@
fun dropTransform() = runBlockingTest {
val drop = Drop<Char>(
loadType = PREPEND,
- count = 0,
+ minPageOffset = 0,
+ maxPageOffset = 0,
placeholdersRemaining = 0
)
@@ -171,10 +175,10 @@
Append(
pages = listOf(
TransformablePage(
- originalPageOffset = 0,
+ originalPageOffsets = intArrayOf(0),
data = listOf("a", "b"),
- originalPageSize = 4,
- originalIndices = listOf(0, 2)
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0, 2)
)
),
placeholdersAfter = 4,
@@ -183,10 +187,10 @@
Append(
pages = listOf(
TransformablePage(
- originalPageOffset = 0,
+ originalPageOffsets = intArrayOf(0),
data = listOf('a', 'b'),
- originalPageSize = 4,
- originalIndices = listOf(0, 2)
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0, 2)
)
),
placeholdersAfter = 4,
@@ -209,10 +213,10 @@
Append(
pages = listOf(
TransformablePage(
- originalPageOffset = 0,
+ originalPageOffsets = intArrayOf(0),
data = listOf('a', 'b', 'd'),
- originalPageSize = 4,
- originalIndices = listOf(0, 1, 3)
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0, 1, 3)
)
),
placeholdersAfter = 4,
@@ -226,10 +230,10 @@
Append(
pages = listOf(
TransformablePage(
- originalPageOffset = 0,
+ originalPageOffsets = intArrayOf(0),
data = listOf('b', 'd'),
- originalPageSize = 4,
- originalIndices = listOf(1, 3)
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(1, 3)
)
),
placeholdersAfter = 4,
@@ -255,10 +259,10 @@
Append(
pages = listOf(
TransformablePage(
- originalPageOffset = 0,
+ originalPageOffsets = intArrayOf(0),
data = listOf("a1", "a2", "b1", "b2"),
- originalPageSize = 2,
- originalIndices = listOf(0, 0, 1, 1)
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0, 0, 1, 1)
)
),
placeholdersAfter = 4,
@@ -275,10 +279,10 @@
Append(
pages = listOf(
TransformablePage(
- originalPageOffset = 0,
+ originalPageOffsets = intArrayOf(0),
data = listOf("a1", "-", "a2", "-", "b1", "-", "b2", "-"),
- originalPageSize = 2,
- originalIndices = listOf(0, 0, 0, 0, 1, 1, 1, 1)
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0, 0, 0, 0, 1, 1, 1, 1)
)
),
placeholdersAfter = 4,
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotStateTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotStateTest.kt
index e0f12f5..30ee3f8 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotStateTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotStateTest.kt
@@ -99,8 +99,22 @@
assertEquals(0, pagerState.placeholdersBefore)
assertEquals(0, pagerState.placeholdersAfter)
- pagerState.drop(loadType = PREPEND, pageCount = 1, placeholdersRemaining = 100)
- pagerState.drop(loadType = APPEND, pageCount = 1, placeholdersRemaining = 100)
+ pagerState.drop(
+ event = PageEvent.Drop(
+ loadType = PREPEND,
+ minPageOffset = -2,
+ maxPageOffset = -2,
+ placeholdersRemaining = 100
+ )
+ )
+ pagerState.drop(
+ event = PageEvent.Drop(
+ loadType = APPEND,
+ minPageOffset = 2,
+ maxPageOffset = 2,
+ placeholdersRemaining = 100
+ )
+ )
assertEquals(0, pagerState.placeholdersBefore)
assertEquals(0, pagerState.placeholdersAfter)
@@ -184,8 +198,22 @@
assertEquals(24, pagerState.placeholdersBefore)
assertEquals(24, pagerState.placeholdersAfter)
- pagerState.drop(loadType = PREPEND, pageCount = 1, placeholdersRemaining = 100)
- pagerState.drop(loadType = APPEND, pageCount = 1, placeholdersRemaining = 100)
+ pagerState.drop(
+ event = PageEvent.Drop(
+ loadType = PREPEND,
+ minPageOffset = -2,
+ maxPageOffset = -2,
+ placeholdersRemaining = 100
+ )
+ )
+ pagerState.drop(
+ event = PageEvent.Drop(
+ loadType = APPEND,
+ minPageOffset = 2,
+ maxPageOffset = 2,
+ placeholdersRemaining = 100
+ )
+ )
assertEquals(100, pagerState.placeholdersBefore)
assertEquals(100, pagerState.placeholdersAfter)
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotTest.kt
index 950424a..ccd230c 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageFetcherSnapshotTest.kt
@@ -157,7 +157,12 @@
assertThat(fetcherState.newEvents()).isEqualTo(
listOf<PageEvent<Int>>(
LoadStateUpdate(APPEND, false, Loading),
- Drop(loadType = PREPEND, count = 1, placeholdersRemaining = 1),
+ Drop(
+ loadType = PREPEND,
+ minPageOffset = -1,
+ maxPageOffset = -1,
+ placeholdersRemaining = 1
+ ),
createAppend(
pageOffset = 1,
range = 3..3,
@@ -239,7 +244,12 @@
endState = NotLoading.Complete
),
LoadStateUpdate(PREPEND, false, Loading),
- Drop(APPEND, 1, 1),
+ Drop(
+ loadType = APPEND,
+ minPageOffset = 1,
+ maxPageOffset = 1,
+ placeholdersRemaining = 1
+ ),
createPrepend(
pageOffset = -1,
range = 96..96,
@@ -408,7 +418,12 @@
LoadStateUpdate(PREPEND, false, Loading),
createPrepend(pageOffset = -1, range = 48..49),
LoadStateUpdate(PREPEND, false, Loading),
- Drop(APPEND, 1, 50),
+ Drop(
+ loadType = APPEND,
+ minPageOffset = 0,
+ maxPageOffset = 0,
+ placeholdersRemaining = 50
+ ),
createPrepend(pageOffset = -2, range = 46..47)
)
@@ -539,7 +554,12 @@
listOf<PageEvent<Int>>(
LoadStateUpdate(PREPEND, false, Loading),
LoadStateUpdate(APPEND, false, Loading),
- Drop(APPEND, 1, 50),
+ Drop(
+ loadType = APPEND,
+ minPageOffset = 0,
+ maxPageOffset = 0,
+ placeholdersRemaining = 50
+ ),
createPrepend(pageOffset = -2, range = 46..47)
)
)
@@ -640,9 +660,19 @@
assertThat(fetcherState.newEvents()).isEqualTo(
listOf<PageEvent<Int>>(
LoadStateUpdate(loadType = APPEND, fromMediator = false, loadState = Loading),
- Drop(loadType = PREPEND, count = 1, placeholdersRemaining = 49),
+ Drop(
+ loadType = PREPEND,
+ minPageOffset = -2,
+ maxPageOffset = -2,
+ placeholdersRemaining = 49
+ ),
createAppend(pageOffset = 1, range = 53..53, endState = Loading),
- Drop(loadType = PREPEND, count = 1, placeholdersRemaining = 50),
+ Drop(
+ loadType = PREPEND,
+ minPageOffset = -1,
+ maxPageOffset = -1,
+ placeholdersRemaining = 50
+ ),
createAppend(pageOffset = 2, range = 54..54)
)
)
@@ -662,7 +692,12 @@
assertThat(fetcherState.newEvents()).isEqualTo(
listOf<PageEvent<Int>>(
LoadStateUpdate(loadType = PREPEND, fromMediator = false, loadState = Loading),
- Drop(loadType = APPEND, count = 1, placeholdersRemaining = 46),
+ Drop(
+ loadType = APPEND,
+ minPageOffset = 2,
+ maxPageOffset = 2,
+ placeholdersRemaining = 46
+ ),
createPrepend(pageOffset = -1, range = 49..49)
)
)
@@ -793,7 +828,12 @@
assertThat(fetcherState.newEvents()).isEqualTo(
listOf<PageEvent<Int>>(
LoadStateUpdate(APPEND, false, Loading),
- Drop(PREPEND, 1, 52),
+ Drop(
+ loadType = PREPEND,
+ minPageOffset = 0,
+ maxPageOffset = 0,
+ placeholdersRemaining = 52
+ ),
createAppend(pageOffset = 2, range = 54..55)
)
)
@@ -842,7 +882,7 @@
createAppend(pageOffset = 2, range = 56..56)
)
- assertEvents(expected, fetcherState.pageEventLists[0])
+ assertThat(fetcherState.pageEventLists[0]).isEqualTo(expected)
fetcherState.job.cancel()
}
}
@@ -913,7 +953,12 @@
listOf<PageEvent<Int>>(
LoadStateUpdate(APPEND, false, Loading),
LoadStateUpdate(PREPEND, false, Loading),
- Drop(PREPEND, 1, 52),
+ Drop(
+ loadType = PREPEND,
+ minPageOffset = 0,
+ maxPageOffset = 0,
+ placeholdersRemaining = 52
+ ),
createAppend(
pageOffset = 2,
range = 54..55,
@@ -982,9 +1027,19 @@
assertThat(fetcherState.newEvents()).isEqualTo(
listOf<PageEvent<Int>>(
LoadStateUpdate(loadType = PREPEND, fromMediator = false, loadState = Loading),
- Drop(loadType = APPEND, count = 1, placeholdersRemaining = 46),
+ Drop(
+ loadType = APPEND,
+ minPageOffset = 2,
+ maxPageOffset = 2,
+ placeholdersRemaining = 46
+ ),
createPrepend(pageOffset = -1, range = 49..49, startState = Loading),
- Drop(loadType = APPEND, count = 1, placeholdersRemaining = 47),
+ Drop(
+ loadType = APPEND,
+ minPageOffset = 1,
+ maxPageOffset = 1,
+ placeholdersRemaining = 47
+ ),
createPrepend(pageOffset = -2, range = 48..48)
)
)
@@ -1004,7 +1059,12 @@
assertThat(fetcherState.newEvents()).isEqualTo(
listOf<PageEvent<Int>>(
LoadStateUpdate(loadType = APPEND, fromMediator = false, loadState = Loading),
- Drop(loadType = PREPEND, count = 1, placeholdersRemaining = 49),
+ Drop(
+ loadType = PREPEND,
+ minPageOffset = -2,
+ maxPageOffset = -2,
+ placeholdersRemaining = 49
+ ),
createAppend(pageOffset = 1, range = 53..53)
)
)
@@ -2058,9 +2118,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf(0),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf(0)
)
),
placeholdersBefore = 0,
@@ -2076,9 +2134,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = -1,
- data = listOf(),
- originalPageSize = 0,
- originalIndices = null
+ data = listOf()
)
),
placeholdersBefore = 0,
@@ -2132,9 +2188,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf(0),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf(0)
)
),
placeholdersBefore = 0,
@@ -2150,9 +2204,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = -1,
- data = listOf(),
- originalPageSize = 0,
- originalIndices = null
+ data = listOf()
)
),
placeholdersBefore = 0,
@@ -2221,9 +2273,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf(1, 2, 3),
- originalPageSize = 3,
- originalIndices = null
+ data = listOf(1, 2, 3)
)
),
placeholdersBefore = 1,
@@ -2239,9 +2289,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = -1,
- data = listOf(0),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf(0)
)
),
placeholdersBefore = 0,
@@ -2258,9 +2306,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = -2,
- data = listOf(),
- originalPageSize = 0,
- originalIndices = null
+ data = listOf()
)
),
placeholdersBefore = 0,
@@ -2316,9 +2362,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf(99),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf(99)
)
),
placeholdersBefore = 99,
@@ -2334,9 +2378,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 1,
- data = listOf(),
- originalPageSize = 0,
- originalIndices = null
+ data = listOf()
)
),
placeholdersAfter = 0,
@@ -2390,9 +2432,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf(99),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf(99)
)
),
placeholdersBefore = 99,
@@ -2408,9 +2448,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 1,
- data = listOf(),
- originalPageSize = 0,
- originalIndices = null
+ data = listOf()
)
),
placeholdersAfter = 0,
@@ -2479,9 +2517,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf(96, 97, 98),
- originalPageSize = 3,
- originalIndices = null
+ data = listOf(96, 97, 98)
)
),
placeholdersBefore = 96,
@@ -2497,9 +2533,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 1,
- data = listOf(99),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf(99)
)
),
placeholdersAfter = 0,
@@ -2516,9 +2550,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 2,
- data = listOf(),
- originalPageSize = 0,
- originalIndices = null
+ data = listOf()
)
),
placeholdersAfter = 0,
@@ -2586,9 +2618,7 @@
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf(50),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf(50)
)
),
placeholdersBefore = 50,
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt
index 9da7abe..f383d13 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagePresenterTest.kt
@@ -20,8 +20,10 @@
import androidx.paging.LoadType.APPEND
import androidx.paging.LoadType.PREPEND
import androidx.paging.LoadType.REFRESH
+import androidx.paging.PageEvent.Insert.Companion.Refresh
import androidx.paging.PagePresenter.ProcessPageEventCallback
import androidx.paging.PagingSource.LoadResult.Page.Companion.COUNT_UNDEFINED
+import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -36,13 +38,11 @@
trailingNullCount: Int = COUNT_UNDEFINED,
indexOfInitialPage: Int = 0
) = PagePresenter(
- PageEvent.Insert.Refresh(
+ Refresh(
pages = pages.mapIndexed { index, list ->
TransformablePage(
originalPageOffset = index - indexOfInitialPage,
- data = list,
- originalPageSize = list.size,
- originalIndices = null
+ data = list
)
},
placeholdersBefore = leadingNullCount,
@@ -68,13 +68,15 @@
internal fun <T : Any> PagePresenter<T>.dropPages(
isPrepend: Boolean,
- pagesToDrop: Int,
+ minPageOffset: Int,
+ maxPageOffset: Int,
placeholdersRemaining: Int,
callback: ProcessPageEventCallback
) = processEvent(
PageEvent.Drop(
loadType = if (isPrepend) PREPEND else APPEND,
- count = pagesToDrop,
+ minPageOffset = minPageOffset,
+ maxPageOffset = maxPageOffset,
placeholdersRemaining = placeholdersRemaining
),
callback
@@ -309,11 +311,16 @@
assertEquals(initialPages.flatten() + List<Char?>(initialNulls) { null }, data.asList())
val callback = ProcessPageEventCallbackCapture()
- data.dropPages(false, pagesToDrop, newNulls, callback)
+ data.dropPages(
+ isPrepend = false,
+ minPageOffset = initialPages.lastIndex - (pagesToDrop - 1),
+ maxPageOffset = initialPages.lastIndex,
+ placeholdersRemaining = newNulls,
+ callback = callback
+ )
- assertEquals(
- events + listOf(StateEvent(APPEND, false, NotLoading.Incomplete)),
- callback.getAllAndClear()
+ assertThat(callback.getAllAndClear()).isEqualTo(
+ events + listOf(StateEvent(APPEND, false, NotLoading.Incomplete))
)
// assert final list state
@@ -345,11 +352,16 @@
)
val callback = ProcessPageEventCallbackCapture()
- data.dropPages(true, pagesToDrop, newNulls, callback)
+ data.dropPages(
+ isPrepend = true,
+ minPageOffset = 0,
+ maxPageOffset = pagesToDrop - 1,
+ placeholdersRemaining = newNulls,
+ callback = callback
+ )
- assertEvents(
- events + listOf(StateEvent(PREPEND, false, NotLoading.Incomplete)),
- callback.getAllAndClear()
+ assertThat(callback.getAllAndClear()).isEqualTo(
+ events + listOf(StateEvent(PREPEND, false, NotLoading.Incomplete))
)
// assert final list state
@@ -370,19 +382,6 @@
}
@Test
- fun dropPageNoop() = verifyDrop(
- initialPages = listOf(
- listOf('a', 'b'),
- listOf('c', 'd')
- ),
- initialNulls = 0,
- newNulls = 0,
- pagesToDrop = 0,
- startEvents = emptyList(),
- endEvents = emptyList()
- )
-
- @Test
fun dropPageMulti() = verifyDrop(
initialPages = listOf(
listOf('a', 'b'),
@@ -420,8 +419,14 @@
initialNulls = 0,
newNulls = 3,
pagesToDrop = 2,
- startEvents = listOf(ChangeEvent(0, 3)),
- endEvents = listOf(ChangeEvent(2, 3))
+ startEvents = listOf(
+ // [null, null, null, 'a', 'b']
+ ChangeEvent(0, 3)
+ ),
+ endEvents = listOf(
+ // ['a', 'b', null, null, null]
+ ChangeEvent(2, 3)
+ )
)
@Test
@@ -435,12 +440,16 @@
newNulls = 4,
pagesToDrop = 2,
startEvents = listOf(
- ChangeEvent(2, 3),
- RemoveEvent(0, 1)
+ // [null, 'e', 'c', 'd', 'a', 'b']
+ RemoveEvent(0, 1),
+ // [null, null, null, null, 'a', 'b']
+ ChangeEvent(1, 3)
),
endEvents = listOf(
- ChangeEvent(2, 3),
- RemoveEvent(6, 1)
+ // ['a', 'b', 'c', 'd', 'e', null]
+ RemoveEvent(6, 1),
+ // ['a', 'b', null, null, null, null]
+ ChangeEvent(2, 3)
)
)
@@ -455,12 +464,16 @@
newNulls = 1,
pagesToDrop = 2,
startEvents = listOf(
- ChangeEvent(2, 1),
- RemoveEvent(0, 2)
+ // ['d', 'a', 'b']
+ RemoveEvent(0, 2),
+ // [null, 'a', 'b']
+ ChangeEvent(0, 1)
),
endEvents = listOf(
- ChangeEvent(2, 1),
- RemoveEvent(3, 2)
+ // ['a', 'b', 'c']
+ RemoveEvent(3, 2),
+ // ['a', 'b', null]
+ ChangeEvent(2, 1)
)
)
@@ -475,14 +488,16 @@
newNulls = 1,
pagesToDrop = 2,
startEvents = listOf(
- ChangeEvent(5, 1),
- RemoveEvent(0, 2),
- RemoveEvent(0, 3)
+ // ['d', 'a', 'b']
+ RemoveEvent(0, 5),
+ // [null, 'a', 'b']
+ ChangeEvent(0, 1)
),
endEvents = listOf(
- ChangeEvent(2, 1),
- RemoveEvent(3, 2),
- RemoveEvent(3, 3)
+ // ['a', 'b', 'c']
+ RemoveEvent(3, 5),
+ // ['a', 'b', null]
+ ChangeEvent(2, 1)
)
)
@@ -507,7 +522,7 @@
@Test
fun snapshot_uncounted() {
val pagePresenter = PagePresenter(
- PageEvent.Insert.Refresh(
+ insertEvent = Refresh(
pages = listOf(TransformablePage(listOf('a'))),
placeholdersBefore = 0,
placeholdersAfter = 0,
@@ -521,7 +536,7 @@
@Test
fun snapshot_counted() {
val pagePresenter = PagePresenter(
- PageEvent.Insert.Refresh(
+ insertEvent = Refresh(
pages = listOf(TransformablePage(listOf('a'))),
placeholdersBefore = 1,
placeholdersAfter = 3,
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagingDataDifferTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagingDataDifferTest.kt
index e5d1060..cfed561 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagingDataDifferTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagingDataDifferTest.kt
@@ -16,8 +16,8 @@
package androidx.paging
-import androidx.paging.LoadType.PREPEND
import androidx.paging.LoadState.NotLoading
+import androidx.paging.LoadType.PREPEND
import androidx.paging.PageEvent.Drop
import androidx.paging.PageEvent.Insert.Companion.Append
import androidx.paging.PageEvent.Insert.Companion.Prepend
@@ -152,7 +152,7 @@
val pageEventFlow = flowOf<PageEvent<Int>>(
Refresh(listOf(), 0, 0, CombinedLoadStates.IDLE_SOURCE),
Prepend(listOf(), 0, CombinedLoadStates.IDLE_SOURCE),
- Drop(PREPEND, 0, 0),
+ Drop(PREPEND, -1, -1, 0),
Refresh(listOf(TransformablePage(0, listOf(0))), 0, 0, CombinedLoadStates.IDLE_SOURCE)
)
@@ -183,7 +183,7 @@
val pageEventFlow = flowOf<PageEvent<Int>>(
Refresh(listOf(), 0, 0, CombinedLoadStates.IDLE_SOURCE),
Prepend(listOf(), 0, CombinedLoadStates.IDLE_SOURCE),
- Drop(PREPEND, 0, 0),
+ Drop(PREPEND, -1, -1, 0),
Refresh(listOf(TransformablePage(0, listOf(0))), 0, 0, CombinedLoadStates.IDLE_SOURCE)
)
@@ -205,7 +205,7 @@
job.cancel()
}
- @Test
+ @Test
fun fetch_loadHintResentWhenUnfulfilled() = testScope.runBlockingTest {
val differ = SimpleDiffer(dummyDifferCallback)
@@ -432,7 +432,14 @@
// Drop the previous page, which reset resendable index state in the PREPEND direction.
// [null, null, [-1], [1], [3], null, null]
- pageEventCh.offer(Drop(loadType = PREPEND, count = 1, placeholdersRemaining = 2))
+ pageEventCh.offer(
+ Drop(
+ loadType = PREPEND,
+ minPageOffset = -2,
+ maxPageOffset = -2,
+ placeholdersRemaining = 2
+ )
+ )
// Re-insert the previous page, which should not trigger resending the index due to
// previous page drop:
diff --git a/paging/common/src/test/kotlin/androidx/paging/SeparatorsTest.kt b/paging/common/src/test/kotlin/androidx/paging/SeparatorsTest.kt
index 8d8bf2b..4edaec7 100644
--- a/paging/common/src/test/kotlin/androidx/paging/SeparatorsTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/SeparatorsTest.kt
@@ -23,6 +23,7 @@
import androidx.paging.PageEvent.Insert.Companion.Append
import androidx.paging.PageEvent.Insert.Companion.Prepend
import androidx.paging.PageEvent.Insert.Companion.Refresh
+import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList
@@ -32,21 +33,6 @@
import org.junit.runners.JUnit4
import kotlin.test.assertEquals
-private fun <T : Any> assertEvents(expected: List<PageEvent<T>>, actual: List<PageEvent<T>>) {
- try {
- assertEquals(expected, actual)
- } catch (e: Throwable) {
- throw AssertionError(
- e.localizedMessage
- .replace("),", "),\n")
- .replace("<[", "<[\n ")
- .replace("actual", "\nactual\n")
- .replace("Expected", "\nExpected\n")
- .replace("pages=", "pages=\n")
- )
- }
-}
-
private fun <T : Any> List<PageEvent<T>>.getItems() = mapNotNull { event ->
when (event) {
is PageEvent.Insert<T> -> event.pages.map { it.data }
@@ -73,34 +59,7 @@
class SeparatorsTest {
@Test
fun refreshFull() = runBlockingTest {
- assertEvents(
- listOf(
- Refresh(
- pages = listOf(
- TransformablePage(
- originalPageOffset = 0,
- data = listOf("a2", "B", "b1"),
- originalPageSize = 2,
- originalIndices = listOf(0, 1, 1)
- ),
- TransformablePage(
- originalPageOffset = 1,
- data = listOf("C"),
- originalPageSize = 2,
- originalIndices = listOf(0)
- ),
- TransformablePage(
- originalPageOffset = 1,
- data = listOf("c1", "c2"),
- originalPageSize = 2,
- originalIndices = null
- )
- ),
- placeholdersBefore = 0,
- placeholdersAfter = 1,
- combinedLoadStates = localLoadStatesOf()
- )
- ),
+ assertThat(
flowOf(
Refresh(
pages = listOf(
@@ -112,6 +71,32 @@
combinedLoadStates = localLoadStatesOf()
)
).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ Refresh(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffsets = intArrayOf(0),
+ data = listOf("a2", "B", "b1"),
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(0, 1),
+ data = listOf("C"),
+ hintOriginalPageOffset = 1,
+ hintOriginalIndices = listOf(0)
+ ),
+ TransformablePage(
+ originalPageOffset = 1,
+ data = listOf("c1", "c2")
+ )
+ ),
+ placeholdersBefore = 0,
+ placeholdersAfter = 1,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
)
}
@@ -125,40 +110,8 @@
placeholdersAfter = 1,
combinedLoadStates = localLoadStatesOf()
)
- assertEvents(
- listOf(
- refresh,
- Prepend(
- pages = listOf(
- TransformablePage(
- originalPageOffset = -2,
- data = listOf("a1", "B", "b1"),
- originalPageSize = 2,
- originalIndices = listOf(0, 1, 1)
- ),
- TransformablePage(
- originalPageOffset = -1,
- data = listOf(),
- originalPageSize = 2,
- originalIndices = null
- ),
- TransformablePage(
- originalPageOffset = -1,
- data = listOf("b2", "b3"),
- originalPageSize = 2,
- originalIndices = null
- ),
- TransformablePage(
- originalPageOffset = -1,
- data = listOf("C"),
- originalPageSize = 2,
- originalIndices = listOf(1) // note: using last index of 2nd page in
- )
- ),
- placeholdersBefore = 1,
- combinedLoadStates = localLoadStatesOf()
- )
- ),
+
+ assertThat(
flowOf(
refresh,
Prepend(
@@ -170,6 +123,32 @@
combinedLoadStates = localLoadStatesOf()
)
).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ refresh,
+ Prepend(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffsets = intArrayOf(-2),
+ data = listOf("a1", "B", "b1"),
+ hintOriginalPageOffset = -2,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffset = -1,
+ data = listOf("b2", "b3")
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(-1, 0),
+ data = listOf("C"),
+ hintOriginalPageOffset = -1,
+ hintOriginalIndices = listOf(1)
+ )
+ ),
+ placeholdersBefore = 1,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
)
}
@@ -183,40 +162,7 @@
placeholdersAfter = 1,
combinedLoadStates = localLoadStatesOf()
)
- assertEvents(
- listOf(
- refresh,
- Append(
- pages = listOf(
- TransformablePage(
- originalPageOffset = 1,
- data = listOf("C"),
- originalPageSize = 2,
- originalIndices = listOf(0)
- ),
- TransformablePage(
- originalPageOffset = 1,
- data = listOf("c1", "D", "d1"),
- originalPageSize = 2,
- originalIndices = listOf(0, 1, 1)
- ),
- TransformablePage(
- originalPageOffset = 2,
- data = listOf(),
- originalPageSize = 2,
- originalIndices = null
- ),
- TransformablePage(
- originalPageOffset = 2,
- data = listOf("d2", "d3"),
- originalPageSize = 2,
- originalIndices = null
- )
- ),
- placeholdersAfter = 1,
- combinedLoadStates = localLoadStatesOf()
- )
- ),
+ assertThat(
flowOf(
refresh,
Append(
@@ -228,41 +174,39 @@
combinedLoadStates = localLoadStatesOf()
)
).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ refresh,
+ Append(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffsets = intArrayOf(0, 1),
+ data = listOf("C"),
+ hintOriginalPageOffset = 1,
+ hintOriginalIndices = listOf(0)
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(1),
+ data = listOf("c1", "D", "d1"),
+ hintOriginalPageOffset = 1,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffset = 2,
+ data = listOf("d2", "d3")
+ )
+ ),
+ placeholdersAfter = 1,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
)
}
@Test
fun refreshDropFull() = runBlockingTest {
- assertEvents(
- expected = listOf(
- Refresh(
- pages = listOf(
- TransformablePage(
- originalPageOffset = 0,
- data = listOf("a1"),
- originalPageSize = 1,
- originalIndices = null
- ),
- TransformablePage(
- originalPageOffset = 1,
- data = listOf(),
- originalPageSize = 1,
- originalIndices = null
- ),
- TransformablePage(
- originalPageOffset = 1,
- data = listOf("a2"),
- originalPageSize = 1,
- originalIndices = null
- )
- ),
- placeholdersBefore = 0,
- placeholdersAfter = 1,
- combinedLoadStates = localLoadStatesOf()
- ),
- Drop<String>(APPEND, 2, 4)
- ),
- actual = flowOf(
+ assertThat(
+ flowOf(
Refresh(
pages = listOf(
listOf("a1"),
@@ -272,8 +216,27 @@
placeholdersAfter = 1,
combinedLoadStates = localLoadStatesOf()
),
- Drop<String>(APPEND, 1, 4)
+ Drop<String>(APPEND, 1, 1, 4)
).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ Refresh(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffset = 0,
+ data = listOf("a1")
+ ),
+ TransformablePage(
+ originalPageOffset = 1,
+ data = listOf("a2")
+ )
+ ),
+ placeholdersBefore = 0,
+ placeholdersAfter = 1,
+ combinedLoadStates = localLoadStatesOf()
+ ),
+ Drop<String>(APPEND, 1, 1, 4)
+ )
)
}
@@ -312,10 +275,12 @@
combinedLoadStates = localLoadStatesOf(appendLocal = append)
)
- private fun drop(
- loadType: LoadType,
- count: Int
- ) = Drop<String>(loadType = loadType, count = count, placeholdersRemaining = 0)
+ private fun drop(loadType: LoadType, minPageOffset: Int, maxPageOffset: Int) = Drop<String>(
+ loadType = loadType,
+ minPageOffset = minPageOffset,
+ maxPageOffset = maxPageOffset,
+ placeholdersRemaining = 0
+ )
@Test
fun refreshNoop() = runBlockingTest {
@@ -433,14 +398,14 @@
listOf(
// not enough data to create separators yet
refresh(pages = listOf()),
- // don't insert a separator, since a drop occurred (even though it's 0 size)
+ // don't insert a separator, since a drop occurred
append(pages = listOf("a1")),
// but now add the separator, since start is done again
prepend(pages = listOf("A"))
),
flowOf(
refresh(pages = listOf(), prepend = NotLoading.Complete),
- drop(loadType = PREPEND, count = 0),
+ drop(loadType = PREPEND, minPageOffset = 0, maxPageOffset = 0),
append(pages = listOf("a1")),
prepend(pages = listOf(), prepend = NotLoading.Complete)
).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
@@ -453,14 +418,14 @@
listOf(
// not enough data to create separators yet
refresh(pages = listOf()),
- // don't insert a separator, since a drop occurred (even though it's 0 size)
+ // don't insert a separator, since a drop occurred
prepend(pages = listOf("a1")),
// but now add the separator, since end is done again
append(pages = listOf("END"))
),
flowOf(
refresh(pages = listOf(), append = NotLoading.Complete),
- drop(loadType = APPEND, count = 0),
+ drop(loadType = APPEND, minPageOffset = 0, maxPageOffset = 0),
prepend(pages = listOf("a1")),
append(pages = listOf(), append = NotLoading.Complete)
).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
@@ -500,96 +465,90 @@
@Test
fun refreshEmptyStartDropFull() = runBlockingTest {
// when start terminal separator is inserted, we need to drop count*2 + 1
- assertEvents(
+ assertThat(
+ flowOf(
+ refresh(
+ pages = listOf("a1", "b1"),
+ prepend = NotLoading.Complete
+ ),
+ drop(loadType = PREPEND, minPageOffset = 0, maxPageOffset = 0)
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
listOf(
Refresh(
pages = listOf(
TransformablePage(
- originalPageOffset = 0,
+ originalPageOffsets = intArrayOf(0),
data = listOf("A"),
- originalPageSize = 1,
- originalIndices = listOf(0)
+ hintOriginalPageOffset = 0,
+ hintOriginalIndices = listOf(0)
),
TransformablePage(
originalPageOffset = 0,
- data = listOf("a1"),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf("a1")
),
TransformablePage(
- originalPageOffset = 1,
+ originalPageOffsets = intArrayOf(0, 1),
data = listOf("B"),
- originalPageSize = 1,
- originalIndices = listOf(0)
+ hintOriginalPageOffset = 1,
+ hintOriginalIndices = listOf(0)
),
TransformablePage(
originalPageOffset = 1,
- data = listOf("b1"),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf("b1")
)
),
placeholdersBefore = 0,
placeholdersAfter = 1,
combinedLoadStates = localLoadStatesOf(prependLocal = NotLoading.Complete)
),
- drop(loadType = PREPEND, count = 3)
- ),
- flowOf(
- refresh(
- pages = listOf("a1", "b1"),
- prepend = NotLoading.Complete
- ),
- drop(loadType = PREPEND, count = 1)
- ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ drop(loadType = PREPEND, minPageOffset = 0, maxPageOffset = 0)
+ )
)
}
@Test
fun refreshEmptyEndDropFull() = runBlockingTest {
// when end terminal separator is inserted, we need to drop count*2 + 1
- assertEvents(
+ assertThat(
+ flowOf(
+ refresh(
+ pages = listOf("a1", "b1"),
+ append = NotLoading.Complete
+ ),
+ drop(loadType = APPEND, minPageOffset = 0, maxPageOffset = 0)
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
listOf(
Refresh(
pages = listOf(
TransformablePage(
originalPageOffset = 0,
- data = listOf("a1"),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf("a1")
),
TransformablePage(
- originalPageOffset = 1,
+ originalPageOffsets = intArrayOf(0, 1),
data = listOf("B"),
- originalPageSize = 1,
- originalIndices = listOf(0)
+ hintOriginalPageOffset = 1,
+ hintOriginalIndices = listOf(0)
),
TransformablePage(
originalPageOffset = 1,
- data = listOf("b1"),
- originalPageSize = 1,
- originalIndices = null
+ data = listOf("b1")
),
TransformablePage(
- originalPageOffset = 1,
+ originalPageOffsets = intArrayOf(1),
data = listOf("END"),
- originalPageSize = 1,
- originalIndices = listOf(0)
+ hintOriginalPageOffset = 1,
+ hintOriginalIndices = listOf(0)
)
),
placeholdersBefore = 0,
placeholdersAfter = 1,
combinedLoadStates = localLoadStatesOf(appendLocal = NotLoading.Complete)
),
- drop(loadType = APPEND, count = 3)
- ),
- flowOf(
- refresh(
- pages = listOf("a1", "b1"),
- append = NotLoading.Complete
- ),
- drop(loadType = APPEND, count = 1)
- ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ drop(loadType = APPEND, minPageOffset = 0, maxPageOffset = 0)
+ )
)
}
@@ -630,6 +589,396 @@
)
}
+ @Test
+ fun refreshEmptyPagesExceptOne() = runBlockingTest {
+ assertThat(
+ flowOf(
+ Refresh(
+ pages = listOf(
+ listOf(),
+ listOf(),
+ listOf("a2", "b1"),
+ listOf(),
+ listOf()
+ ).toTransformablePages(),
+ placeholdersBefore = 0,
+ placeholdersAfter = 1,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ Refresh(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffset = 0,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffset = 1,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(2),
+ data = listOf("a2", "B", "b1"),
+ hintOriginalPageOffset = 2,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffset = 3,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffset = 4,
+ data = listOf()
+ )
+ ),
+ placeholdersBefore = 0,
+ placeholdersAfter = 1,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
+ )
+ }
+
+ @Test
+ fun refreshSparsePages() = runBlockingTest {
+ assertThat(
+ flowOf(
+ Refresh(
+ pages = listOf(
+ listOf(),
+ listOf("a2", "b1"),
+ listOf(),
+ listOf("c1", "c2"),
+ listOf()
+ ).toTransformablePages(),
+ placeholdersBefore = 0,
+ placeholdersAfter = 1,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ Refresh(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffset = 0,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(1),
+ data = listOf("a2", "B", "b1"),
+ hintOriginalPageOffset = 1,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffset = 2,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(1, 3),
+ data = listOf("C"),
+ hintOriginalPageOffset = 3,
+ hintOriginalIndices = listOf(0)
+ ),
+ TransformablePage(
+ originalPageOffset = 3,
+ data = listOf("c1", "c2")
+ ),
+ TransformablePage(
+ originalPageOffset = 4,
+ data = listOf()
+ )
+ ),
+ placeholdersBefore = 0,
+ placeholdersAfter = 1,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
+ )
+ }
+
+ @Test
+ fun prependEmptyPagesExceptOne() = runBlockingTest {
+ val refresh = Refresh(
+ pages = listOf(
+ listOf("c1", "c2")
+ ).toTransformablePages(),
+ placeholdersBefore = 2,
+ placeholdersAfter = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+
+ assertThat(
+ flowOf(
+ refresh,
+ Prepend(
+ pages = listOf(
+ listOf(),
+ listOf(),
+ listOf("a1", "b1"),
+ listOf(),
+ listOf()
+ ).toTransformablePages(5),
+ placeholdersBefore = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ refresh,
+ Prepend(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffset = -5,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffset = -4,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(-3),
+ data = listOf("a1", "B", "b1"),
+ hintOriginalPageOffset = -3,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(-3, 0),
+ data = listOf("C"),
+ hintOriginalPageOffset = -3,
+ hintOriginalIndices = listOf(1)
+ ),
+ TransformablePage(
+ originalPageOffset = -2,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffset = -1,
+ data = listOf()
+ )
+ ),
+ placeholdersBefore = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
+ )
+ }
+
+ @Test
+ fun prependSparsePages() = runBlockingTest {
+ val refresh = Refresh(
+ pages = listOf(
+ listOf("d1", "d2")
+ ).toTransformablePages(),
+ placeholdersBefore = 0,
+ placeholdersAfter = 4,
+ combinedLoadStates = localLoadStatesOf()
+ )
+
+ assertThat(
+ flowOf(
+ refresh,
+ Prepend(
+ pages = listOf(
+ listOf(),
+ listOf("a1", "b1"),
+ listOf(),
+ listOf("c1", "c2"),
+ listOf()
+ ).toTransformablePages(5),
+ placeholdersBefore = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ refresh,
+ Prepend(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffset = -5,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(-4),
+ data = listOf("a1", "B", "b1"),
+ hintOriginalPageOffset = -4,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffset = -3,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(-4, -2),
+ data = listOf("C"),
+ hintOriginalPageOffset = -4,
+ hintOriginalIndices = listOf(1)
+ ),
+ TransformablePage(
+ originalPageOffset = -2,
+ data = listOf("c1", "c2")
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(-2, 0),
+ data = listOf("D"),
+ hintOriginalPageOffset = -2,
+ hintOriginalIndices = listOf(1)
+ ),
+ TransformablePage(
+ originalPageOffset = -1,
+ data = listOf()
+ )
+ ),
+ placeholdersBefore = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
+ )
+ }
+
+ @Test
+ fun appendEmptyPagesExceptOne() = runBlockingTest {
+ val refresh = Refresh(
+ pages = listOf(
+ listOf("a1", "a2")
+ ).toTransformablePages(),
+ placeholdersBefore = 0,
+ placeholdersAfter = 2,
+ combinedLoadStates = localLoadStatesOf()
+ )
+
+ assertThat(
+ flowOf(
+ refresh,
+ Append(
+ pages = listOf(
+ listOf(),
+ listOf(),
+ listOf("b1", "c1"),
+ listOf(),
+ listOf()
+ ).toTransformablePages(-1),
+ placeholdersAfter = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ refresh,
+ Append(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffset = 1,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffset = 2,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(0, 3),
+ data = listOf("B"),
+ hintOriginalPageOffset = 3,
+ hintOriginalIndices = listOf(0)
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(3),
+ data = listOf("b1", "C", "c1"),
+ hintOriginalPageOffset = 3,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffset = 4,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffset = 5,
+ data = listOf()
+ )
+ ),
+ placeholdersAfter = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
+ )
+ }
+
+ @Test
+ fun appendSparsePages() = runBlockingTest {
+ val refresh = Refresh(
+ pages = listOf(
+ listOf("a1", "a2")
+ ).toTransformablePages(),
+ placeholdersBefore = 0,
+ placeholdersAfter = 4,
+ combinedLoadStates = localLoadStatesOf()
+ )
+
+ assertThat(
+ flowOf(
+ refresh,
+ Append(
+ pages = listOf(
+ listOf(),
+ listOf("b1", "c1"),
+ listOf(),
+ listOf("d1", "d2"),
+ listOf()
+ ).toTransformablePages(-1),
+ placeholdersAfter = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ ).insertEventSeparators(LETTER_SEPARATOR_GENERATOR).toList()
+ ).isEqualTo(
+ listOf(
+ refresh,
+ Append(
+ pages = listOf(
+ TransformablePage(
+ originalPageOffset = 1,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(0, 2),
+ data = listOf("B"),
+ hintOriginalPageOffset = 2,
+ hintOriginalIndices = listOf(0)
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(2),
+ data = listOf("b1", "C", "c1"),
+ hintOriginalPageOffset = 2,
+ hintOriginalIndices = listOf(0, 1, 1)
+ ),
+ TransformablePage(
+ originalPageOffset = 3,
+ data = listOf()
+ ),
+ TransformablePage(
+ originalPageOffsets = intArrayOf(2, 4),
+ data = listOf("D"),
+ hintOriginalPageOffset = 4,
+ hintOriginalIndices = listOf(0)
+ ),
+ TransformablePage(
+ originalPageOffset = 4,
+ data = listOf("d1", "d2")
+ ),
+ TransformablePage(
+ originalPageOffset = 5,
+ data = listOf()
+ )
+ ),
+ placeholdersAfter = 0,
+ combinedLoadStates = localLoadStatesOf()
+ )
+ )
+ )
+ }
+
companion object {
/**
* Creates an upper-case letter at the beginning of each section of strings that start
diff --git a/paging/common/src/test/kotlin/androidx/paging/SeparatorsWithRemoteMediatorTest.kt b/paging/common/src/test/kotlin/androidx/paging/SeparatorsWithRemoteMediatorTest.kt
index fb4dae7..9a314ab 100644
--- a/paging/common/src/test/kotlin/androidx/paging/SeparatorsWithRemoteMediatorTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/SeparatorsWithRemoteMediatorTest.kt
@@ -170,10 +170,10 @@
originalPageOffset: Int,
data: List<String>
) = TransformablePage(
- originalPageOffset = originalPageOffset,
+ originalPageOffsets = intArrayOf(originalPageOffset),
data = data,
- originalPageSize = data.size,
- originalIndices = data.fold(mutableListOf()) { acc, s ->
+ hintOriginalPageOffset = originalPageOffset,
+ hintOriginalIndices = data.fold(mutableListOf()) { acc, s ->
acc.apply {
add(when {
acc.isEmpty() -> 0
diff --git a/paging/common/src/test/kotlin/androidx/paging/TestPagingSourceExt.kt b/paging/common/src/test/kotlin/androidx/paging/TestPagingSourceExt.kt
index d2b8fa7..da362a1 100644
--- a/paging/common/src/test/kotlin/androidx/paging/TestPagingSourceExt.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/TestPagingSourceExt.kt
@@ -68,8 +68,6 @@
) = listOf(
TransformablePage(
originalPageOffset = pageOffset,
- data = ITEMS.slice(range),
- originalPageSize = range.count(),
- originalIndices = null
+ data = ITEMS.slice(range)
)
)
diff --git a/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java b/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java
index 5344523..cec547f 100644
--- a/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java
+++ b/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java
@@ -26,11 +26,13 @@
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.TextView;
@@ -223,10 +225,21 @@
/**
* Sets the required flags on the dialog window to enable input method window to show up.
+ * <p>
+ * Note that starting from Android R, the new WindowInsets API supports showing soft-input
+ * on-demand, so there is no longer a need to rely on the
+ * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE} flag to show the
+ * soft-input when there is no focused editor.</p>
*/
private void requestInputMethod(Dialog dialog) {
- Window window = dialog.getWindow();
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ // TODO:(b/163914595) Remove the dependency of STATE_ALWAYS_VISIBLE for pre-R.
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ Window window = dialog.getWindow();
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ } else {
+ dialog.getWindow().getDecorView().getWindowInsetsController()
+ .show(WindowInsets.Type.ime());
+ }
}
/**
diff --git a/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragmentCompat.java b/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragmentCompat.java
index fbf4b728..c628b8d 100644
--- a/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragmentCompat.java
+++ b/preference/preference/src/main/java/androidx/preference/PreferenceDialogFragmentCompat.java
@@ -25,10 +25,12 @@
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.TextView;
@@ -203,10 +205,21 @@
/**
* Sets the required flags on the dialog window to enable input method window to show up.
+ * <p>
+ * Note that starting from Android R, the new WindowInsets API supports showing soft-input
+ * on-demand, so there is no longer a need to rely on the
+ * {@link WindowManager.LayoutParams#SOFT_INPUT_STATE_ALWAYS_VISIBLE} flag to show the
+ * soft-input when there is no focused editor.</p>
*/
private void requestInputMethod(Dialog dialog) {
- Window window = dialog.getWindow();
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ // TODO:(b/163914595) Remove the dependency of STATE_ALWAYS_VISIBLE for pre-R.
+ Window window = dialog.getWindow();
+ window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ } else {
+ dialog.getWindow().getDecorView().getWindowInsetsController()
+ .show(WindowInsets.Type.ime());
+ }
}
/**
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index d1448a5..7e0f442 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -646,6 +646,9 @@
* pre-packaged database schema utilizing the exported schema files generated when
* {@link Database#exportSchema()} is enabled.
* <p>
+ * The {@link Callback#onOpen(SupportSQLiteDatabase)} method can be used as an indicator
+ * that the pre-packaged database was successfully opened by Room and can be cleaned up.
+ * <p>
* This method is not supported for an in memory database {@link Builder}.
*
* @param databaseFile The database file.
@@ -669,6 +672,9 @@
* pre-packaged database schema utilizing the exported schema files generated when
* {@link Database#exportSchema()} is enabled.
* <p>
+ * The {@link Callback#onOpen(SupportSQLiteDatabase)} method can be used as an indicator
+ * that the pre-packaged database was successfully opened by Room and can be cleaned up.
+ * <p>
* This method is not supported for an in memory database {@link Builder}.
*
* @param databaseFile The database file.
@@ -692,17 +698,23 @@
* <p>
* This is useful for processing compressed database files. Room does not open the
* pre-packaged database, instead it copies it into the internal app database folder, and
- * then open it.
+ * then open it. The {@link InputStream} will be closed once Room is done consuming it.
* <p>
* The pre-packaged database schema will be validated. It might be best to create your
* pre-packaged database schema utilizing the exported schema files generated when
* {@link Database#exportSchema()} is enabled.
* <p>
- * This method is not supported for an in memory database {@link Builder}. The underlying
- * {@link InputStream} will be closed.
+ * The {@link Callback#onOpen(SupportSQLiteDatabase)} method can be used as an indicator
+ * that the pre-packaged database was successfully opened by Room and can be cleaned up.
+ * <p>
+ * This method is not supported for an in memory database {@link Builder}.
*
* @param inputStreamCallable A callable that returns an InputStream from which to copy
- * the database.
+ * the database. The callable will be invoked in a thread from
+ * the Executor set via {@link #setQueryExecutor(Executor)}. The
+ * callable is only invoked if Room needs to create and open the
+ * database from the pre-package database, usually the first time
+ * it is created or during a destructive migration.
*
* @return This {@link Builder} instance.
*/
@@ -720,17 +732,23 @@
* <p>
* This is useful for processing compressed database files. Room does not open the
* pre-packaged database, instead it copies it into the internal app database folder, and
- * then open it.
+ * then open it. The {@link InputStream} will be closed once Room is done consuming it.
* <p>
* The pre-packaged database schema will be validated. It might be best to create your
* pre-packaged database schema utilizing the exported schema files generated when
* {@link Database#exportSchema()} is enabled.
* <p>
- * This method is not supported for an in memory database {@link Builder}. The underlying
- * {@link InputStream} will be closed.
+ * The {@link Callback#onOpen(SupportSQLiteDatabase)} method can be used as an indicator
+ * that the pre-packaged database was successfully opened by Room and can be cleaned up.
+ * <p>
+ * This method is not supported for an in memory database {@link Builder}.
*
* @param inputStreamCallable A callable that returns an InputStream from which to copy
- * the database.
+ * the database. The callable will be invoked in a thread from
+ * the Executor set via {@link #setQueryExecutor(Executor)}. The
+ * callable is only invoked if Room needs to create and open the
+ * database from the pre-package database, usually the first time
+ * it is created or during a destructive migration.
* @param callback The pre-packaged callback.
*
* @return This {@link Builder} instance.
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoAdapter.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoAdapter.java
index 94be45d..94131b5 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoAdapter.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoAdapter.java
@@ -20,18 +20,16 @@
import android.content.Context;
import android.net.Uri;
-import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.util.Predicate;
import androidx.recyclerview.selection.ItemKeyProvider;
import androidx.recyclerview.selection.SelectionTracker;
import androidx.recyclerview.widget.RecyclerView;
import com.example.android.supportv7.Cheeses;
-import com.example.android.supportv7.R;
import java.util.ArrayList;
import java.util.Collections;
@@ -47,13 +45,15 @@
// Our list of thingies. Our DemoHolder subclasses extract display
// values directly from the Uri, so we only need this simple list.
// The list also contains entries for alphabetical section headers.
- private final List<Uri> mCheeses;
+ private final List<Uri> mCheeses = new ArrayList<>();
+ private boolean mSmallItemLayout;
+ private boolean mAllCheesesEnabled;
// This default implementation must be replaced
// with a real implementation in #bindSelectionHelper.
- private SelectionTest mSelTest = new SelectionTest() {
+ private Predicate<Uri> mIsSelectedTest = new Predicate<Uri>() {
@Override
- public boolean isSelected(Uri id) {
+ public boolean test(Uri key) {
throw new IllegalStateException(
"Adapter must be initialized with SelectionTracker");
}
@@ -61,7 +61,6 @@
DemoAdapter(Context context) {
mContext = context;
- mCheeses = createCheeseList("CheeseKindom");
mKeyProvider = new KeyProvider(mCheeses);
// In the fancy edition of selection support we supply access to stable
@@ -77,22 +76,14 @@
// Glue together SelectionTracker and the adapter.
public void bindSelectionTracker(final SelectionTracker<Uri> tracker) {
checkArgument(tracker != null);
- mSelTest = new SelectionTest() {
+ mIsSelectedTest = new Predicate<Uri>() {
@Override
- public boolean isSelected(Uri id) {
- return tracker.isSelected(id);
+ public boolean test(Uri key) {
+ return tracker.isSelected(key);
}
};
}
- void loadData() {
- onDataReady();
- }
-
- private void onDataReady() {
- notifyDataSetChanged();
- }
-
@Override
public int getItemCount() {
return mCheeses.size();
@@ -105,22 +96,21 @@
@Override
public void onBindViewHolder(@NonNull DemoHolder holder, int position) {
- if (holder instanceof DemoHeaderHolder) {
- Uri uri = mKeyProvider.getKey(position);
- ((DemoHeaderHolder) holder).update(uri.getPathSegments().get(0));
- } else if (holder instanceof DemoItemHolder) {
- Uri uri = mKeyProvider.getKey(position);
- ((DemoItemHolder) holder).update(uri, uri.getPathSegments().get(1),
- mSelTest.isSelected(uri));
+ Uri uri = mKeyProvider.getKey(position);
+ holder.update(uri);
+ if (holder instanceof DemoItemHolder) {
+ DemoItemHolder itemHolder = (DemoItemHolder) holder;
+ itemHolder.setSelected(mIsSelectedTest.test(uri));
+ itemHolder.setSmallLayoutMode(mSmallItemLayout);
}
}
@Override
public int getItemViewType(int position) {
- Uri key = mKeyProvider.getKey(position);
- if (key.getPathSegments().size() == 1) {
+ Uri uri = mKeyProvider.getKey(position);
+ if (Uris.isGroup(uri)) {
return TYPE_HEADER;
- } else if (key.getPathSegments().size() == 2) {
+ } else if (Uris.isCheese(uri)) {
return TYPE_ITEM;
}
@@ -131,57 +121,32 @@
public DemoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
switch (viewType) {
case TYPE_HEADER:
- return new DemoHeaderHolder(
- inflateLayout(mContext, parent, R.layout.selection_demo_list_header));
+ return new DemoHeaderHolder(mContext, parent);
case TYPE_ITEM:
- return new DemoItemHolder(
- inflateLayout(mContext, parent, R.layout.selection_demo_list_item));
+ return new DemoItemHolder(mContext, parent);
}
throw new RuntimeException("Unsupported view type" + viewType);
}
- @SuppressWarnings("TypeParameterUnusedInFormals") // Convenience to avoid clumsy cast.
- private static <V extends View> V inflateLayout(
- Context context, ViewGroup parent, int layout) {
-
- return (V) LayoutInflater.from(context).inflate(layout, parent, false);
- }
-
// Creates a list of cheese Uris and section header Uris.
- private static List<Uri> createCheeseList(String authority) {
- List<Uri> cheeses = new ArrayList<>();
- char section = '-'; // any ol' value other than 'a' will do the trick here.
+ private void populateCheeses(int maxItemsPerGroup) {
+ String group = "-"; // any ol' value other than 'a' will do the trick here.
+ int itemsInGroup = 0;
for (String cheese : Cheeses.sCheeseStrings) {
- char leadingChar = cheese.toLowerCase().charAt(0);
+ String leadingChar = Character.toString(cheese.toLowerCase().charAt(0));
// When we find a new leading character insert an artificial
// cheese header
- if (leadingChar != section) {
- section = leadingChar;
- Uri headerUri = new Uri.Builder()
- .scheme("content")
- .encodedAuthority(authority)
- .appendPath(Character.toString(section))
- .build();
-
- cheeses.add(headerUri);
+ if (!leadingChar.equals(group)) {
+ group = leadingChar;
+ itemsInGroup = 0;
+ mCheeses.add(Uris.forGroup(group));
}
-
- Uri itemUri = new Uri.Builder()
- .scheme("content")
- .encodedAuthority(authority)
- .appendPath(Character.toString(section))
- .appendPath(cheese)
- .build();
- cheeses.add(itemUri);
+ if (++itemsInGroup <= maxItemsPerGroup) {
+ mCheeses.add(Uris.forCheese(group, cheese));
+ }
}
-
- return cheeses;
- }
-
- private interface SelectionTest {
- boolean isSelected(Uri id);
}
public boolean removeItem(Uri key) {
@@ -195,6 +160,30 @@
return removed != null;
}
+ void enableSmallItemLayout(boolean enabled) {
+ mSmallItemLayout = enabled;
+ }
+
+ void enableAllCheeses(boolean enabled) {
+ mAllCheesesEnabled = enabled;
+ }
+
+ boolean smallItemLayoutEnabled() {
+ return mSmallItemLayout;
+ }
+
+ boolean allCheesesEnabled() {
+ return mAllCheesesEnabled;
+ }
+
+
+
+ void refresh() {
+ mCheeses.clear();
+ populateCheeses(mAllCheesesEnabled ? Integer.MAX_VALUE : 5);
+ notifyDataSetChanged();
+ }
+
/**
* When ever possible provide the selection library with a
* "SCOPED_MAPPED" ItemKeyProvider. This enables the selection
@@ -211,13 +200,13 @@
private final List<Uri> mData;
- KeyProvider(List<Uri> cheeses) {
+ KeyProvider(List<Uri> data) {
// Advise the world we can supply ids/position for any item at any time,
// not just when visible in RecyclerView.
// This enables fancy stuff especially helpful to users with pointy
// devices like Chromebooks, or tablets with touch pads
super(SCOPE_MAPPED);
- mData = cheeses;
+ mData = data;
}
@Override
@@ -228,13 +217,7 @@
@Override
public int getPosition(@NonNull Uri key) {
int position = Collections.binarySearch(mData, key);
- // position is insertion point if key is missing.
- // Since the insertion point could be end of the list + 1
- // both verify the position is in bounds, and that the value
- // at position is the same as the key.
- return position >= 0 && position <= mData.size() - 1 && key.equals(mData.get(position))
- ? position
- : RecyclerView.NO_POSITION;
+ return position >= 0 ? position : RecyclerView.NO_POSITION;
}
}
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHeaderHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHeaderHolder.java
index be78dd0..0e64018 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHeaderHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHeaderHolder.java
@@ -15,26 +15,32 @@
*/
package com.example.android.supportv7.widget.selection.fancy;
-import android.view.View;
+import android.content.Context;
+import android.net.Uri;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
-import androidx.annotation.Nullable;
+import androidx.annotation.NonNull;
import com.example.android.supportv7.R;
final class DemoHeaderHolder extends DemoHolder {
- private static final String HEADER_TAG = "I'm a header";
final TextView mLabel;
- DemoHeaderHolder(LinearLayout layout) {
+ DemoHeaderHolder(@NonNull Context context, @NonNull ViewGroup parent) {
+ this(inflateLayout(context, parent, R.layout.selection_demo_list_header));
+ }
+
+ private DemoHeaderHolder(LinearLayout layout) {
super(layout);
- layout.setTag(HEADER_TAG);
mLabel = layout.findViewById(R.id.label);
}
- void update(String label) {
+ @Override
+ void update(@NonNull Uri uri) {
+ String label = Uris.getGroup(uri);
mLabel.setText(label.toUpperCase() + label + label + "...");
}
@@ -42,8 +48,4 @@
public String toString() {
return "Header{name:" + mLabel.getText() + "}";
}
-
- static boolean isHeader(@Nullable View view) {
- return view == null ? false : HEADER_TAG.equals(view.getTag());
- }
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHolder.java
index 0c6b999..fd8d494 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoHolder.java
@@ -16,12 +16,25 @@
package com.example.android.supportv7.widget.selection.fancy;
+import android.content.Context;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
+import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
abstract class DemoHolder extends RecyclerView.ViewHolder {
DemoHolder(LinearLayout layout) {
super(layout);
}
+
+ abstract void update(@NonNull Uri uri);
+
+ @SuppressWarnings("TypeParameterUnusedInFormals") // Convenience to avoid clumsy cast.
+ static <V extends View> V inflateLayout(Context context, ViewGroup parent, int layout) {
+ return (V) LayoutInflater.from(context).inflate(layout, parent, false);
+ }
}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoItemHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoItemHolder.java
index 176fb3d..88e932e 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoItemHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/DemoItemHolder.java
@@ -15,12 +15,16 @@
*/
package com.example.android.supportv7.widget.selection.fancy;
+import android.content.Context;
import android.graphics.Rect;
import android.net.Uri;
import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Dimension;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
@@ -36,7 +40,11 @@
private @Nullable Uri mKey;
- DemoItemHolder(LinearLayout layout) {
+ DemoItemHolder(@NonNull Context context, @NonNull ViewGroup parent) {
+ this(inflateLayout(context, parent, R.layout.selection_demo_list_item));
+ }
+
+ private DemoItemHolder(LinearLayout layout) {
super(layout);
mContainer = layout.findViewById(R.id.container);
@@ -71,13 +79,18 @@
};
}
- void update(Uri key, String label, boolean selected) {
- mKey = key;
- mLabel.setText(label);
- setSelected(selected);
+ @Override
+ void update(@NonNull Uri uri) {
+ mKey = uri;
+ mLabel.setText(Uris.getCheese(uri));
}
- private void setSelected(boolean selected) {
+ void setSmallLayoutMode(boolean small) {
+ mSelector.setVisibility(small ? View.GONE : View.VISIBLE);
+ mLabel.setTextSize(Dimension.SP, small ? 14f : 20f);
+ }
+
+ void setSelected(boolean selected) {
mContainer.setActivated(selected);
mSelector.setActivated(selected);
}
@@ -108,8 +121,8 @@
boolean inSelectRegion(MotionEvent e) {
Rect iconRect = new Rect();
- mSelector.getGlobalVisibleRect(iconRect);
- return iconRect.contains((int) e.getRawX(), (int) e.getRawY());
+ return mSelector.getGlobalVisibleRect(iconRect)
+ && iconRect.contains((int) e.getRawX(), (int) e.getRawY());
}
ItemDetails<Uri> getItemDetails() {
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
index 5da1896..3be459a 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
@@ -72,7 +72,6 @@
private SelectionTracker<Uri> mSelectionTracker;
private GridLayoutManager mLayout;
- private boolean mIterceptListenerEnabled = false;
private boolean mSwipeDuringSelectionEnabled = false;
@Override
@@ -82,12 +81,23 @@
setContentView(R.layout.selection_demo_layout);
mRecView = (RecyclerView) findViewById(R.id.list);
- // Demo how to intercept touch events before selection tracker.
- // In case you need to do something fancy that selection tracker
- // might otherwise interfere with.
- setupCustomTouchListener();
-
mLayout = new GridLayoutManager(this, 1);
+
+ // Let our headers span any number of columns.
+ mLayout.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ switch(mAdapter.getItemViewType(position)){
+ case DemoAdapter.TYPE_HEADER:
+ return mLayout.getSpanCount();
+
+ case DemoAdapter.TYPE_ITEM:
+ default:
+ return 1;
+ }
+ }
+ });
+
mRecView.setLayoutManager(mLayout);
mAdapter = new DemoAdapter(this);
mRecView.setAdapter(mAdapter);
@@ -209,42 +219,31 @@
});
}
- // If you want to provided special handling of clicks on items
- // in RecyclerView (respond to a play button, or show a menu
- // when a three-dot menu is clicked) you can't just add an OnClickListener
- // to the View. This is because Selection lib installs an
- // OnItemTouchListener w/ RecyclerView, and that listener eats
- // up many of the touch/mouse events RecyclerView sends its way.
- // To work around this install your own OnItemTouchListener *before*
- // you build your SelectionTracker instance. That'll give your listener
- // a chance to intercept events before Selection lib gobbles them up.
- private void setupCustomTouchListener() {
- mRecView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
- @Override
- public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
- return mIterceptListenerEnabled
- && DemoHeaderHolder.isHeader(rv.findChildViewUnder(e.getX(), e.getY()));
- }
-
- @Override
- public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
- toast(FancySelectionDemoActivity.this, "Clicked on a header!");
- }
-
- @Override
- public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
- }
- });
- }
-
@Override
protected void onSaveInstanceState(@NonNull Bundle state) {
super.onSaveInstanceState(state);
mSelectionTracker.onSaveInstanceState(state);
+ state.putBoolean("showAll", mAdapter.allCheesesEnabled());
+ state.putBoolean("gridLayout", mAdapter.smallItemLayoutEnabled());
+ state.putBoolean("enableSwipe", mSwipeDuringSelectionEnabled);
}
- private void updateFromSavedState(Bundle state) {
+ private void updateFromSavedState(@Nullable Bundle state) {
mSelectionTracker.onRestoreInstanceState(state);
+
+ boolean showAll = false;
+ boolean gridLayout = false;
+ if (state == null) {
+ mSwipeDuringSelectionEnabled = true;
+ } else {
+ showAll = state.getBoolean("showAll");
+ gridLayout = state.getBoolean("gridLayout");
+ mSwipeDuringSelectionEnabled = state.getBoolean("enableSwipe");
+ }
+
+ mAdapter.enableAllCheeses(showAll);
+ mLayout.setSpanCount(gridLayout ? 2 : 1);
+ mAdapter.enableSmallItemLayout(gridLayout);
}
@Override
@@ -252,22 +251,41 @@
boolean showMenu = super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.selection_demo_actions, menu);
for (int i = 0; i < menu.size(); i++) {
- updateOptionFromMenu(menu.getItem(i));
+ MenuItem item = menu.getItem(i);
+ switch (item.getItemId()) {
+ case R.id.option_menu_more_cheese:
+ item.setChecked(mAdapter.allCheesesEnabled());
+ break;
+ case R.id.option_menu_grid_layout:
+ item.setChecked(mAdapter.smallItemLayoutEnabled());
+ break;
+ case R.id.option_menu_swipe_during_select:
+ item.setChecked(mSwipeDuringSelectionEnabled);
+ break;
+ }
}
return showMenu;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- item.setChecked(!item.isChecked());
+ if (item.isCheckable()) {
+ item.setChecked(!item.isChecked());
+ }
updateOptionFromMenu(item);
return true;
}
private void updateOptionFromMenu(@NonNull MenuItem item) {
switch (item.getItemId()) {
- case R.id.option_menu_custom_listener:
- mIterceptListenerEnabled = item.isChecked();
+ case R.id.option_menu_more_cheese:
+ mAdapter.enableAllCheeses(item.isChecked());
+ mAdapter.refresh();
+ break;
+ case R.id.option_menu_grid_layout:
+ mAdapter.enableSmallItemLayout(item.isChecked());
+ mLayout.setSpanCount(item.isChecked() ? 2 : 1);
+ mAdapter.refresh();
break;
case R.id.option_menu_swipe_during_select:
mSwipeDuringSelectionEnabled = item.isChecked();
@@ -329,7 +347,7 @@
@Override
protected void onStart() {
super.onStart();
- mAdapter.loadData();
+ mAdapter.refresh();
}
// Tracking focus separately from explicit selection
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/Uris.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/Uris.java
new file mode 100644
index 0000000..ca9cd57
--- /dev/null
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/Uris.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.widget.selection.fancy;
+
+import android.net.Uri;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Preconditions;
+
+final class Uris {
+
+ private Uris() {}
+
+ static final String SCHEME = "content";
+ static final String AUTHORITY = "CheeseWorld";
+ static final String PARAM_GROUP = "g";
+ static final String PARAM_CHEESE = "c";
+
+ static @NonNull Uri forGroup(@NonNull String group) {
+ return new Uri.Builder()
+ .scheme(SCHEME)
+ .encodedAuthority(AUTHORITY)
+ .appendQueryParameter(PARAM_GROUP, group)
+ .build();
+ }
+
+ static @NonNull Uri forCheese(@NonNull String group, @NonNull String cheese) {
+ return new Uri.Builder()
+ .scheme(SCHEME)
+ .encodedAuthority(AUTHORITY)
+ .appendQueryParameter(PARAM_GROUP, group)
+ .appendQueryParameter(PARAM_CHEESE, cheese)
+ .build();
+ }
+
+ static boolean isGroup(@NonNull Uri uri) {
+ return !isCheese(uri);
+ }
+
+ static boolean isCheese(@NonNull Uri uri) {
+ return uri.getQueryParameter(PARAM_GROUP) != null
+ && uri.getQueryParameter(PARAM_CHEESE) != null;
+ }
+
+ static @NonNull String getGroup(@NonNull Uri uri) {
+ String group = uri.getQueryParameter(PARAM_GROUP);
+ Preconditions.checkArgument(group != null);
+ return group;
+ }
+
+ static @NonNull String getCheese(@NonNull Uri uri) {
+ Preconditions.checkArgument(isCheese(uri));
+ return uri.getQueryParameter(PARAM_CHEESE);
+ }
+}
diff --git a/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml b/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml
index c800127..3e6959d 100644
--- a/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml
+++ b/samples/Support7Demos/src/main/res/color/selection_demo_item_selector.xml
@@ -17,8 +17,8 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_activated="false"
- android:color="?android:attr/colorForeground"
- android:alpha=".3"
+ android:color="@android:color/black"
+ android:alpha=".1"
/>
<item
android:state_activated="true"
diff --git a/samples/Support7Demos/src/main/res/layout/selection_demo_layout.xml b/samples/Support7Demos/src/main/res/layout/selection_demo_layout.xml
index 3fc1f40..27e08bf 100644
--- a/samples/Support7Demos/src/main/res/layout/selection_demo_layout.xml
+++ b/samples/Support7Demos/src/main/res/layout/selection_demo_layout.xml
@@ -55,7 +55,9 @@
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:paddingTop="5dp"
- android:scrollbars="none" />
+ android:background="#11000000"
+ android:scrollbarStyle="insideOverlay"
+ android:scrollbars="vertical" />
</FrameLayout>
diff --git a/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml b/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml
index fb5e8e9..e28e922 100644
--- a/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml
+++ b/samples/Support7Demos/src/main/res/layout/selection_demo_list_item.xml
@@ -40,8 +40,8 @@
</TextView>
<TextView
android:id="@+id/label"
- android:textSize="20sp"
- android:textStyle="bold"
+ android:textSize="18sp"
+ android:textColor="@android:color/black"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp"
diff --git a/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml b/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml
index 17ea335..7751f3e 100644
--- a/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml
+++ b/samples/Support7Demos/src/main/res/menu/selection_demo_actions.xml
@@ -16,13 +16,15 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
- android:id="@+id/option_menu_swipe_during_select"
- android:title="Swipe When Selection Is Active"
- android:checkable="true"
- android:checked="true"/>
+ android:id="@+id/option_menu_more_cheese"
+ android:title="Show all the cheeses!"
+ android:checkable="true"/>
<item
- android:id="@+id/option_menu_custom_listener"
- android:title="Custom OnItemTouchListener"
- android:checkable="true"
- android:checked="false"/>
+ android:id="@+id/option_menu_grid_layout"
+ android:title="Grid layout please!"
+ android:checkable="true"/>
+ <item
+ android:id="@+id/option_menu_swipe_during_select"
+ android:title="Swipe when stuff is selected!"
+ android:checkable="true"/>
</menu>
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt
index 9b9ea21..e3f3171 100644
--- a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt
@@ -23,7 +23,6 @@
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteStatement
import androidx.inspection.ArtToolInterface
-import androidx.inspection.InspectorEnvironment
import androidx.sqlite.inspection.SqliteInspectorProtocol.DatabasePossiblyChangedEvent
import androidx.sqlite.inspection.SqliteInspectorProtocol.Event.OneOfCase.DATABASE_POSSIBLY_CHANGED
import androidx.test.core.app.ApplicationProvider
@@ -202,7 +201,7 @@
this.first { it.originMethod == m && it is Hook.EntryHook }.asEntryHook
@Suppress("UNCHECKED_CAST")
- private fun List<Hook>.exitHookFor(m: String): InspectorEnvironment.ExitHook<Any> =
+ private fun List<Hook>.exitHookFor(m: String): ArtToolInterface.ExitHook<Any> =
this.first { it.originMethod == m && it is Hook.ExitHook }
- .asExitHook as InspectorEnvironment.ExitHook<Any>
+ .asExitHook as ArtToolInterface.ExitHook<Any>
}
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/TrackDatabasesTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/TrackDatabasesTest.kt
index 389a221..c5f40b9 100644
--- a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/TrackDatabasesTest.kt
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/TrackDatabasesTest.kt
@@ -20,7 +20,7 @@
import android.database.sqlite.SQLiteClosable
import android.database.sqlite.SQLiteDatabase
import android.os.Build
-import androidx.inspection.InspectorEnvironment.ExitHook
+import androidx.inspection.ArtToolInterface.ExitHook
import androidx.sqlite.inspection.SqliteInspectorProtocol.Event
import androidx.sqlite.inspection.SqliteInspectorProtocol.Response
import androidx.sqlite.inspection.test.MessageFactory.createKeepDatabasesOpenCommand
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/EntryExitMatchingHookRegistry.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/EntryExitMatchingHookRegistry.java
index 0ee785f..58db50f 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/EntryExitMatchingHookRegistry.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/EntryExitMatchingHookRegistry.java
@@ -20,6 +20,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.inspection.ArtToolInterface.EntryHook;
+import androidx.inspection.ArtToolInterface.ExitHook;
import androidx.inspection.InspectorEnvironment;
import java.util.ArrayDeque;
@@ -54,8 +56,8 @@
void registerHook(Class<?> originClass, final String originMethod,
final OnExitCallback onExitCallback) {
- mEnvironment.registerEntryHook(originClass, originMethod,
- new InspectorEnvironment.EntryHook() {
+ mEnvironment.artTI().registerEntryHook(originClass, originMethod,
+ new EntryHook() {
@SuppressLint("SyntheticAccessor")
@Override
public void onEntry(@Nullable Object thisObject,
@@ -64,8 +66,8 @@
}
});
- mEnvironment.registerExitHook(originClass, originMethod,
- new InspectorEnvironment.ExitHook<Object>() {
+ mEnvironment.artTI().registerExitHook(originClass, originMethod,
+ new ExitHook<Object>() {
@SuppressLint("SyntheticAccessor")
@Override
public Object onExit(Object result) {
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java
index 08cf69e..0631878 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/RoomInvalidationRegistry.java
@@ -92,7 +92,8 @@
if (mInvoker == null) {
cached = Collections.emptyList();
} else {
- List<?> instances = mEnvironment.findInstances(mInvoker.invalidationTrackerClass);
+ List<?> instances =
+ mEnvironment.artTI().findInstances(mInvoker.invalidationTrackerClass);
cached = new ArrayList<>(instances.size());
for (Object instance : instances) {
cached.add(new WeakReference<>(instance));
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java
index 9f7ad85..7b6c815 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqlDelightInvalidation.java
@@ -55,7 +55,7 @@
return;
}
// invalidating all queries because we can't say which ones were actually affected.
- List<?> queries = mEnvironment.findInstances(mQueryClass);
+ List<?> queries = mEnvironment.artTI().findInstances(mQueryClass);
for (Object query: queries) {
notifyDataChanged(query);
}
diff --git a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java
index 13c0bc3..16195d9 100644
--- a/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java
+++ b/sqlite/sqlite-inspection/src/main/java/androidx/sqlite/inspection/SqliteInspector.java
@@ -44,6 +44,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.inspection.ArtToolInterface.EntryHook;
+import androidx.inspection.ArtToolInterface.ExitHook;
import androidx.inspection.Connection;
import androidx.inspection.Inspector;
import androidx.inspection.InspectorEnvironment;
@@ -252,7 +254,7 @@
registerDatabaseClosedHooks(hookRegistry);
// Check for database instances in memory
- for (SQLiteDatabase instance : mEnvironment.findInstances(SQLiteDatabase.class)) {
+ for (SQLiteDatabase instance : mEnvironment.artTI().findInstances(SQLiteDatabase.class)) {
/** the race condition here will be handled by mDatabaseRegistry */
if (instance.isOpen()) {
onDatabaseOpened(instance);
@@ -262,7 +264,7 @@
}
// Check for database instances on disk
- for (Application instance : mEnvironment.findInstances(Application.class)) {
+ for (Application instance : mEnvironment.artTI().findInstances(Application.class)) {
for (String name : instance.databaseList()) {
File path = instance.getDatabasePath(name);
if (path.exists() && !isHelperSqliteFile(path)) {
@@ -296,8 +298,8 @@
OPEN_DATABASE_COMMAND_SIGNATURE_API_11,
CREATE_IN_MEMORY_DATABASE_COMMAND_SIGNATURE_API_27);
- InspectorEnvironment.ExitHook<SQLiteDatabase> hook =
- new InspectorEnvironment.ExitHook<SQLiteDatabase>() {
+ ExitHook<SQLiteDatabase> hook =
+ new ExitHook<SQLiteDatabase>() {
@SuppressLint("SyntheticAccessor")
@Override
public SQLiteDatabase onExit(SQLiteDatabase database) {
@@ -316,15 +318,15 @@
}
};
for (String method : methods) {
- mEnvironment.registerExitHook(SQLiteDatabase.class, method, hook);
+ mEnvironment.artTI().registerExitHook(SQLiteDatabase.class, method, hook);
}
}
private void registerReleaseReferenceHooks() {
- mEnvironment.registerEntryHook(
+ mEnvironment.artTI().registerEntryHook(
SQLiteClosable.class,
"releaseReference()V",
- new InspectorEnvironment.EntryHook() {
+ new EntryHook() {
@Override
public void onEntry(@Nullable Object thisObject,
@NonNull List<Object> args) {
@@ -374,8 +376,8 @@
* {@link SQLiteDatabase#setTransactionSuccessful} was called
*/
private void registerInvalidationHooksTransaction(final RequestCollapsingThrottler throttler) {
- mEnvironment.registerExitHook(SQLiteDatabase.class, "endTransaction()V",
- new InspectorEnvironment.ExitHook<Object>() {
+ mEnvironment.artTI().registerExitHook(SQLiteDatabase.class, "endTransaction()V",
+ new ExitHook<Object>() {
@Override
public Object onExit(Object result) {
throttler.submitRequest();
@@ -395,8 +397,8 @@
private void registerInvalidationHooksSqliteStatement(
final RequestCollapsingThrottler throttler) {
for (String method : SQLITE_STATEMENT_EXECUTE_METHODS_SIGNATURES) {
- mEnvironment.registerExitHook(SQLiteStatement.class, method,
- new InspectorEnvironment.ExitHook<Object>() {
+ mEnvironment.artTI().registerExitHook(SQLiteStatement.class, method,
+ new ExitHook<Object>() {
@Override
public Object onExit(Object result) {
throttler.submitRequest();
diff --git a/ui/settings.gradle b/ui/settings.gradle
index 57520eb..5aade6c 100644
--- a/ui/settings.gradle
+++ b/ui/settings.gradle
@@ -46,10 +46,10 @@
includeProject(":compose:compose-compiler", "../compose/compose-compiler")
includeProject(":compose:compose-compiler-hosted", "../compose/compose-compiler-hosted")
includeProject(":compose:compose-compiler-hosted:integration-tests", "../compose/compose-compiler-hosted/integration-tests")
-includeProject(":compose:runtime:runtime-dispatch", "../compose/compose-dispatch")
-includeProject(":compose:runtime:runtime", "../compose/compose-runtime")
-includeProject(":compose:runtime:runtime:benchmark", "../compose/compose-runtime/compose-runtime-benchmark")
-includeProject(":compose:runtime:runtime:samples", "../compose/compose-runtime/samples")
+includeProject(":compose:runtime:runtime-dispatch", "../compose/runtime/runtime-dispatch")
+includeProject(":compose:runtime:runtime", "../compose/runtime/runtime")
+includeProject(":compose:runtime:runtime:benchmark", "../compose/runtime/runtime/compose-runtime-benchmark")
+includeProject(":compose:runtime:runtime:samples", "../compose/runtime/runtime/samples")
includeProject(":compose:runtime", "../compose/runtime")
includeProject(":lint-checks", "../lint-checks")
includeProject(":tracing", "../tracing")
@@ -65,11 +65,11 @@
includeProject(":compose:android-view:android-view:integration-tests:android-view-demos", "ui-android-view/integration-tests/android-view-demos")
includeProject(":compose:android-view:android-view:samples", "ui-android-view/samples")
includeProject(":compose:animation", "../compose/animation")
-includeProject(":compose:animation:animation", "ui-animation")
-includeProject(":compose:animation:animation-core", "ui-animation-core")
-includeProject(":compose:animation:animation-core:samples", "ui-animation-core/samples")
-includeProject(":compose:animation:animation:integration-tests:animation-demos", "ui-animation/integration-tests/animation-demos")
-includeProject(":compose:animation:animation:samples", "ui-animation/samples")
+includeProject(":compose:animation:animation", "../compose/animation/animation")
+includeProject(":compose:animation:animation-core", "../compose/animation/animation-core")
+includeProject(":compose:animation:animation-core:samples", "../compose/animation/animation-core/samples")
+includeProject(":compose:animation:animation:integration-tests:animation-demos", "../compose/animation/animation/integration-tests/animation-demos")
+includeProject(":compose:animation:animation:samples", "../compose/animation/animation/samples")
includeProject(":ui", "ui")
includeProject(":ui:ui-animation-tooling-internal", "ui-animation-tooling-internal")
includeProject(":compose:ui:ui", "ui-core")
@@ -113,13 +113,13 @@
includeProject(":compose:ui:ui-unit", "ui-unit")
includeProject(":compose:ui:ui-unit:samples", "ui-unit/samples")
includeProject(":compose:ui:ui-util", "ui-util")
-includeProject(":compose:runtime:runtime-saved-instance-state", "ui-saved-instance-state")
-includeProject(":compose:runtime:runtime-saved-instance-state:samples", "ui-saved-instance-state/samples")
-includeProject(":compose:runtime:runtime-livedata", "ui-livedata")
-includeProject(":compose:runtime:runtime-livedata:samples", "ui-livedata/samples")
+includeProject(":compose:runtime:runtime-saved-instance-state", "../compose/runtime/runtime-saved-instance-state")
+includeProject(":compose:runtime:runtime-saved-instance-state:samples", "../compose/runtime/runtime-saved-instance-state/samples")
+includeProject(":compose:runtime:runtime-livedata", "../compose/runtime/runtime-livedata")
+includeProject(":compose:runtime:runtime-livedata:samples", "../compose/runtime/runtime-livedata/samples")
includeProject(":test-screenshot", "../test/screenshot")
-includeProject(":compose:runtime:runtime-rxjava2", "ui-rxjava2")
-includeProject(":compose:runtime:runtime-rxjava2:samples", "ui-rxjava2/samples")
+includeProject(":compose:runtime:runtime-rxjava2", "../compose/runtime/runtime-rxjava2")
+includeProject(":compose:runtime:runtime-rxjava2:samples", "../compose/runtime/runtime-rxjava2/samples")
includeProject(":compose:test-utils", "../compose/test-utils")
includeProject(":compose:ui:ui-viewbinding", "ui-core-viewbinding")
includeProject(":compose:ui:ui-viewbinding:samples", "ui-core-viewbinding/samples")
diff --git a/ui/ui-animation/api/res-0.1.0-dev04.txt b/ui/ui-animation/api/res-0.1.0-dev04.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev04.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev05.txt b/ui/ui-animation/api/res-0.1.0-dev05.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev05.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev06.txt b/ui/ui-animation/api/res-0.1.0-dev06.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev06.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev07.txt b/ui/ui-animation/api/res-0.1.0-dev07.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev07.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev08.txt b/ui/ui-animation/api/res-0.1.0-dev08.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev08.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev09.txt b/ui/ui-animation/api/res-0.1.0-dev09.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev09.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev10.txt b/ui/ui-animation/api/res-0.1.0-dev10.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev10.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev11.txt b/ui/ui-animation/api/res-0.1.0-dev11.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev11.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev12.txt b/ui/ui-animation/api/res-0.1.0-dev12.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev12.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev14.txt b/ui/ui-animation/api/res-0.1.0-dev14.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev14.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev15.txt b/ui/ui-animation/api/res-0.1.0-dev15.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev15.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-0.1.0-dev16.txt b/ui/ui-animation/api/res-0.1.0-dev16.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-0.1.0-dev16.txt
+++ /dev/null
diff --git a/ui/ui-animation/api/res-current.txt b/ui/ui-animation/api/res-current.txt
deleted file mode 100644
index e69de29..0000000
--- a/ui/ui-animation/api/res-current.txt
+++ /dev/null
diff --git a/ui/ui-core/build.gradle b/ui/ui-core/build.gradle
index aff8277..b49e2e0 100644
--- a/ui/ui-core/build.gradle
+++ b/ui/ui-core/build.gradle
@@ -113,6 +113,16 @@
implementation project(":compose:foundation:foundation-layout")
implementation project(":compose:foundation:foundation")
}
+
+ desktopTest.dependencies {
+ implementation(TRUTH)
+ implementation(JUNIT)
+ implementation(MOCKITO_CORE)
+ implementation MOCKITO_KOTLIN, {
+ exclude group: 'org.mockito' // to keep control on the mockito version
+ }
+ implementation(SKIKO_CURRENT_OS)
+ }
}
}
diff --git a/ui/ui-core/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt b/ui/ui-core/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
index fc5b7d8..c20e8d8 100644
--- a/ui/ui-core/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
+++ b/ui/ui-core/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
@@ -166,16 +166,23 @@
container.invalidate()
}
+ // Don't inline these variables into snapshotObserver.observeReads,
+ // because observeReads requires that onChanged should always be the same instance.
+ // Otherwise there will be a memory leak and FPS drop (see b/163905871)
+ private val onCommitAffectingLayout = ::onRequestRelayout
+ private val onCommitAffectingMeasure = ::onRequestMeasure
+ private val onCommitAffectingLayer = OwnedLayer::invalidate
+
override fun observeLayoutModelReads(node: LayoutNode, block: () -> Unit) {
- snapshotObserver.observeReads(node, ::onRequestRelayout, block)
+ snapshotObserver.observeReads(node, onCommitAffectingLayout, block)
}
override fun observeMeasureModelReads(node: LayoutNode, block: () -> Unit) {
- snapshotObserver.observeReads(node, ::onRequestMeasure, block)
+ snapshotObserver.observeReads(node, onCommitAffectingMeasure, block)
}
private fun observeDrawModelReads(layer: SkijaLayer, block: () -> Unit) {
- snapshotObserver.observeReads(layer, OwnedLayer::invalidate, block)
+ snapshotObserver.observeReads(layer, onCommitAffectingLayer, block)
}
override fun createLayer(
diff --git a/ui/ui-core/src/desktopTest/kotlin/androidx/compose/ui/platform/DesktopOwnerTest.kt b/ui/ui-core/src/desktopTest/kotlin/androidx/compose/ui/platform/DesktopOwnerTest.kt
new file mode 100644
index 0000000..b571ab0
--- /dev/null
+++ b/ui/ui-core/src/desktopTest/kotlin/androidx/compose/ui/platform/DesktopOwnerTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 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.platform
+
+import androidx.compose.runtime.ExperimentalComposeApi
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.ui.node.ExperimentalLayoutNodeApi
+import androidx.compose.ui.node.LayoutNode
+import com.nhaarman.mockitokotlin2.doAnswer
+import com.nhaarman.mockitokotlin2.doReturn
+import com.nhaarman.mockitokotlin2.mock
+import org.jetbrains.skiko.Library
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+@OptIn(ExperimentalLayoutNodeApi::class, ExperimentalComposeApi::class)
+class DesktopOwnerTest {
+ @Test
+ fun `single invalidate with multiple observers and single state change`() {
+ Library.load("/", "skiko")
+
+ var invalidateCount = 0
+
+ val owners = mock<DesktopOwners> {
+ on { platformInputService } doReturn mock()
+ on { invalidate() }.doAnswer { invalidateCount++; Unit }
+ }
+ val owner = DesktopOwner(owners)
+ val node = LayoutNode()
+ val state = mutableStateOf(2)
+
+ owner.observeLayoutModelReads(node) {
+ state.value
+ }
+
+ owner.observeLayoutModelReads(node) {
+ state.value
+ }
+
+ val oldInvalidateCount = invalidateCount
+
+ Snapshot.notifyObjectsInitialized()
+ state.value++
+ Snapshot.sendApplyNotifications()
+
+ assertEquals(1, invalidateCount - oldInvalidateCount)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-core/src/desktopTest/resources/mockito-extensions/org.mockito.plugins.MockMaker b/ui/ui-core/src/desktopTest/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..ca6ee9c
--- /dev/null
+++ b/ui/ui-core/src/desktopTest/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file
diff --git a/ui/ui-desktop/build.gradle b/ui/ui-desktop/build.gradle
index efea5fd..d99bc31 100644
--- a/ui/ui-desktop/build.gradle
+++ b/ui/ui-desktop/build.gradle
@@ -60,9 +60,7 @@
resources.srcDirs += new File(SupportConfigKt.getExternalProjectPath(project), "noto-fonts/other/")
resources.srcDirs += "src/jvmTest/res"
dependencies {
- implementation(SKIKO_WINDOWS)
- implementation(SKIKO_LINUX)
- implementation(SKIKO_MACOS)
+ implementation(SKIKO_CURRENT_OS)
implementation(TRUTH)
}
}
diff --git a/ui/ui-desktop/samples/build.gradle b/ui/ui-desktop/samples/build.gradle
index 9320e0c..c11ed39 100644
--- a/ui/ui-desktop/samples/build.gradle
+++ b/ui/ui-desktop/samples/build.gradle
@@ -40,9 +40,7 @@
}
jvmMain.dependencies {
- implementation(SKIKO_WINDOWS)
- implementation(SKIKO_LINUX)
- implementation(SKIKO_MACOS)
+ implementation(SKIKO_CURRENT_OS)
implementation project(":compose:desktop:desktop")
}
}
diff --git a/ui/ui-foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldCursorTest.kt b/ui/ui-foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldCursorTest.kt
index d10d774..b073db6 100644
--- a/ui/ui-foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldCursorTest.kt
+++ b/ui/ui-foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldCursorTest.kt
@@ -46,7 +46,6 @@
import org.junit.Test
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
-import kotlin.math.roundToInt
@LargeTest
@OptIn(
@@ -142,19 +141,19 @@
}
private fun Bitmap.assertCursor(cursorWidth: Dp, density: Density) {
- val halfCursorWidth = (with(density) { cursorWidth.toIntPx() } / 2f).roundToInt()
+ val сursorWidth = (with(density) { cursorWidth.toIntPx() })
val width = width
val height = height
this.assertPixels(
IntSize(width, height)
) { position ->
- if (position.x >= halfCursorWidth - 1 && position.x < halfCursorWidth + 1) {
+ if (position.x >= сursorWidth - 1 && position.x < сursorWidth + 1) {
// skip some pixels around cursor
null
} else if (position.y < 5 || position.y > height - 5) {
// skip some pixels vertically
null
- } else if (position.x in 0..halfCursorWidth) {
+ } else if (position.x in 0..сursorWidth) {
// cursor
Color.Red
} else {
diff --git a/ui/ui-foundation/src/commonMain/kotlin/androidx/compose/foundation/BaseTextField.kt b/ui/ui-foundation/src/commonMain/kotlin/androidx/compose/foundation/BaseTextField.kt
index b78fc90..0a15d0c 100644
--- a/ui/ui-foundation/src/commonMain/kotlin/androidx/compose/foundation/BaseTextField.kt
+++ b/ui/ui-foundation/src/commonMain/kotlin/androidx/compose/foundation/BaseTextField.kt
@@ -237,7 +237,8 @@
0f, 0f,
cursorWidth, cursorHeight
)
- val cursorX = (cursorRect.left + cursorRect.right) / 2
+ val cursorX = (cursorRect.left + cursorWidth / 2)
+ .coerceAtMost(size.width - cursorWidth / 2)
drawLine(
color.value,
diff --git a/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt b/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
index 8459fd4..32b1e38 100644
--- a/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
+++ b/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
@@ -530,9 +530,9 @@
val cursorXOffset = col * fontSizeInPx
val expectRect = Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = top,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = top + fontSizeInPx
)
val actualRect = paragraph.getCursorRect(i)
@@ -548,9 +548,9 @@
val cursorXOffset = col * fontSizeInPx
val expectRect = Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = top,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = top + fontSizeInPx
)
val actualRect = paragraph.getCursorRect(text.length)
diff --git a/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt b/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
index 6c61b7e..e8fbb6b 100644
--- a/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
+++ b/ui/ui-text-core/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
@@ -65,8 +65,6 @@
private val resourceLoader = TestFontResourceLoader(context)
- private val cursorWidth = 4f
-
@Test
fun empty_string() {
with(defaultDensity) {
@@ -588,9 +586,9 @@
val cursorXOffset = i * fontSizeInPx
assertThat(cursorRect).isEqualTo(
Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = 0f,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = fontSizeInPx
)
)
@@ -615,9 +613,9 @@
val cursorXOffset = i * fontSizeInPx
assertThat(paragraph.getCursorRect(i)).isEqualTo(
Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = 0f,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = fontSizeInPx
)
)
@@ -627,9 +625,9 @@
val cursorXOffset = (i % charsPerLine) * fontSizeInPx
assertThat(paragraph.getCursorRect(i)).isEqualTo(
Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = fontSizeInPx,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = fontSizeInPx * 2.2f
)
)
@@ -651,9 +649,9 @@
// Cursor before '\n'
assertThat(paragraph.getCursorRect(3)).isEqualTo(
Rect(
- left = 3 * fontSizeInPx - cursorWidth / 2,
+ left = 3 * fontSizeInPx,
top = 0f,
- right = 3 * fontSizeInPx + cursorWidth / 2,
+ right = 3 * fontSizeInPx,
bottom = fontSizeInPx
)
)
@@ -661,9 +659,9 @@
// Cursor after '\n'
assertThat(paragraph.getCursorRect(4)).isEqualTo(
Rect(
- left = -cursorWidth / 2,
+ left = 0f,
top = fontSizeInPx,
- right = cursorWidth / 2,
+ right = 0f,
bottom = fontSizeInPx * 2.2f
)
)
@@ -684,9 +682,9 @@
// Cursor before '\n'
assertThat(paragraph.getCursorRect(3)).isEqualTo(
Rect(
- left = 3 * fontSizeInPx - cursorWidth / 2,
+ left = 3 * fontSizeInPx,
top = 0f,
- right = 3 * fontSizeInPx + cursorWidth / 2,
+ right = 3 * fontSizeInPx,
bottom = fontSizeInPx
)
)
@@ -694,9 +692,9 @@
// Cursor after '\n'
assertThat(paragraph.getCursorRect(4)).isEqualTo(
Rect(
- left = -cursorWidth / 2,
+ left = 0f,
top = fontSizeInPx,
- right = cursorWidth / 2,
+ right = 0f,
bottom = fontSizeInPx * 2.2f
)
)
@@ -719,9 +717,9 @@
val cursorXOffset = (text.length - i) * fontSizeInPx
assertThat(paragraph.getCursorRect(i)).isEqualTo(
Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = 0f,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = fontSizeInPx
)
)
@@ -746,9 +744,9 @@
val cursorXOffset = (charsPerLine - i) * fontSizeInPx
assertThat(paragraph.getCursorRect(i)).isEqualTo(
Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = 0f,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = fontSizeInPx
)
)
@@ -758,9 +756,9 @@
val cursorXOffset = (charsPerLine - i % charsPerLine) * fontSizeInPx
assertThat(paragraph.getCursorRect(i)).isEqualTo(
Rect(
- left = cursorXOffset - cursorWidth / 2,
+ left = cursorXOffset,
top = fontSizeInPx,
- right = cursorXOffset + cursorWidth / 2,
+ right = cursorXOffset,
bottom = fontSizeInPx * 2.2f
)
)
@@ -783,9 +781,9 @@
// Cursor before '\n'
assertThat(paragraph.getCursorRect(3)).isEqualTo(
Rect(
- left = 0 - cursorWidth / 2,
+ left = 0f,
top = 0f,
- right = 0 + cursorWidth / 2,
+ right = 0f,
bottom = fontSizeInPx
)
)
@@ -793,9 +791,9 @@
// Cursor after '\n'
assertThat(paragraph.getCursorRect(4)).isEqualTo(
Rect(
- left = 3 * fontSizeInPx - cursorWidth / 2,
+ left = 3 * fontSizeInPx,
top = fontSizeInPx,
- right = 3 * fontSizeInPx + cursorWidth / 2,
+ right = 3 * fontSizeInPx,
bottom = fontSizeInPx * 2.2f
)
)
@@ -818,9 +816,9 @@
// Cursor before '\n'
assertThat(paragraph.getCursorRect(3)).isEqualTo(
Rect(
- left = 0 - cursorWidth / 2,
+ left = 0f,
top = 0f,
- right = 0 + cursorWidth / 2,
+ right = 0f,
bottom = fontSizeInPx
)
)
@@ -828,9 +826,9 @@
// Cursor after '\n'
assertThat(paragraph.getCursorRect(4)).isEqualTo(
Rect(
- left = -cursorWidth / 2,
+ left = 0f,
top = fontSizeInPx,
- right = +cursorWidth / 2,
+ right = 0f,
bottom = fontSizeInPx * 2.2f
)
)
diff --git a/ui/ui-text-core/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt b/ui/ui-text-core/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
index 8665c44..abff882 100644
--- a/ui/ui-text-core/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
+++ b/ui/ui-text-core/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
@@ -256,14 +256,15 @@
if (offset !in 0..charSequence.length) {
throw AssertionError("offset($offset) is out of bounds (0,${charSequence.length}")
}
- val cursorWidth = 4.0f
val horizontal = layout.getPrimaryHorizontal(offset)
val line = layout.getLineForOffset(offset)
+ // The width of the cursor is not taken into account. The callers of this API should use
+ // rect.left to get the start X position and then adjust it according to the width if needed
return Rect(
- horizontal - 0.5f * cursorWidth,
+ horizontal,
layout.getLineTop(line),
- horizontal + 0.5f * cursorWidth,
+ horizontal,
layout.getLineBottom(line)
)
}
diff --git a/wear/wear/src/androidTest/java/androidx/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java b/wear/wear/src/androidTest/java/androidx/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java
index 6887f25..9d48837 100644
--- a/wear/wear/src/androidTest/java/androidx/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java
+++ b/wear/wear/src/androidTest/java/androidx/wear/widget/drawer/WearableDrawerLayoutEspressoTest.java
@@ -31,7 +31,9 @@
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@@ -250,6 +252,49 @@
}
@Test
+ public void drawerContentViewShouldOnlyInflateOnceOpened() {
+ // GIVEN a launched activity with only an action drawer
+ activityRule.launchActivity(
+ new DrawerTestActivity.Builder()
+ .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
+ .build());
+
+ final RecyclerView actionList =
+ activityRule.getActivity().findViewById(R.id.action_list);
+
+ // WHEN it is opened
+ WearableDrawerView actionDrawer = activityRule.getActivity().findViewById(
+ R.id.action_drawer);
+ openDrawer(actionDrawer);
+
+ // THEN the action drawer should be open and the items should all exist in the actionList
+ // adapter
+ onView(withId(R.id.action_drawer))
+ .perform(
+ waitForMatchingView(
+ allOf(withId(R.id.action_drawer), isOpened(true)),
+ MAX_WAIT_MS));
+ assertEquals(7, actionList.getAdapter().getItemCount());
+ }
+
+ @Test
+ public void drawerContentViewShouldNotInflateAfterLaunch() {
+ // GIVEN a launched activity with only an action drawer
+ activityRule.launchActivity(
+ new DrawerTestActivity.Builder()
+ .setStyle(DrawerStyle.ONLY_ACTION_DRAWER_WITH_TITLE)
+ .build());
+
+ final RecyclerView actionList =
+ activityRule.getActivity().findViewById(R.id.action_list);
+
+ // THEN the drawer should not be visible and the draw action list should not have an
+ // adapter set
+ onView(allOf(withId(R.id.action_list), not(isDisplayed())));
+ assertNull(actionList.getAdapter());
+ }
+
+ @Test
public void navDrawerShouldOpenWhenCalledInOnCreateAndThenCloseWhenRequested() {
// GIVEN an activity which calls openDrawer(Gravity.TOP) in onCreate, then closes it
// WHEN it is launched
diff --git a/wear/wear/src/main/java/androidx/wear/widget/drawer/WearableActionDrawerView.java b/wear/wear/src/main/java/androidx/wear/widget/drawer/WearableActionDrawerView.java
index 4d8439e..191d502 100644
--- a/wear/wear/src/main/java/androidx/wear/widget/drawer/WearableActionDrawerView.java
+++ b/wear/wear/src/main/java/androidx/wear/widget/drawer/WearableActionDrawerView.java
@@ -185,14 +185,18 @@
.getDimensionPixelOffset(R.dimen.ws_action_drawer_item_icon_right_margin);
mActionList = new RecyclerView(context);
+ mActionList.setId(R.id.action_list);
mActionList.setLayoutManager(new LinearLayoutManager(context));
mActionListAdapter = new ActionListAdapter(getMenu());
- mActionList.setAdapter(mActionListAdapter);
+ // Do not bind the mActionListAdapter to the action list here. We will bind it when/if the
+ // drawer is first opened to avoid the inflation cost in the case that the drawer is never
+ // used
setDrawerContent(mActionList);
}
@Override
public void onDrawerOpened() {
+ setContentIfFirstCall();
if (mActionListAdapter.getItemCount() > 0) {
RecyclerView.ViewHolder holder = mActionList.findViewHolderForAdapterPosition(0);
if (holder != null && holder.itemView != null) {
@@ -201,6 +205,12 @@
}
}
+ private void setContentIfFirstCall() {
+ if (mActionList.getAdapter() == null) {
+ mActionList.setAdapter(mActionListAdapter);
+ }
+ }
+
@Override
public boolean canScrollHorizontally(int direction) {
// Prevent the window from being swiped closed while it is open by saying that it can scroll
diff --git a/wear/wear/src/main/res/values/ids.xml b/wear/wear/src/main/res/values/ids.xml
index 8a7324e..6341805 100644
--- a/wear/wear/src/main/res/values/ids.xml
+++ b/wear/wear/src/main/res/values/ids.xml
@@ -15,4 +15,5 @@
-->
<resources>
<item name="ws_navigation_drawer_view_pager" type="id" />
+ <item name="action_list" type="id" />
</resources>
diff --git a/work/workmanager-inspection/src/main/java/androidx/work/inspection/WorkManagerInspector.kt b/work/workmanager-inspection/src/main/java/androidx/work/inspection/WorkManagerInspector.kt
index d74a194..791320c 100644
--- a/work/workmanager-inspection/src/main/java/androidx/work/inspection/WorkManagerInspector.kt
+++ b/work/workmanager-inspection/src/main/java/androidx/work/inspection/WorkManagerInspector.kt
@@ -59,24 +59,23 @@
private val stackTraceMap = mutableMapOf<String, Array<StackTraceElement>>()
init {
- workManager = environment.findInstances(Application::class.java).first()
+ workManager = environment.artTI().findInstances(Application::class.java).first()
.let { application -> WorkManager.getInstance(application) as WorkManagerImpl }
Handler(Looper.getMainLooper()).post {
lifecycleRegistry.currentState = Lifecycle.State.STARTED
}
- environment.registerEntryHook(
+ environment.artTI().registerEntryHook(
WorkContinuationImpl::class.java,
- "enqueue()Landroidx/work/Operation;",
- InspectorEnvironment.EntryHook { obj, _ ->
- val stackTrace = Throwable().stackTrace
- executor.submit {
- (obj as? WorkContinuationImpl)?.allIds?.forEach { id ->
- stackTraceMap[id] = stackTrace.prune()
- }
- }
+ "enqueue()Landroidx/work/Operation;"
+ ) { obj, _ ->
+ val stackTrace = Throwable().stackTrace
+ executor.submit {
+ (obj as? WorkContinuationImpl)?.allIds?.forEach { id ->
+ stackTraceMap[id] = stackTrace.prune()
+ }
}
- )
+ }
}
override fun onReceiveCommand(data: ByteArray, callback: CommandCallback) {