Merge "Document setTargetRotation for ImageCapture" into androidx-master-dev
diff --git a/OWNERS b/OWNERS
index 71b2ab2..67a6139 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,4 @@
adamp@google.com
-jsproch@google.com
alanv@google.com
asfalcone@google.com
aurimas@google.com
@@ -8,7 +7,9 @@
emberrose@google.com
ilake@google.com
jeffrygaston@google.com
+jsproch@google.com
kirillg@google.com
+lpf@google.com
mount@google.com
nickanthony@google.com
obenabde@google.com
diff --git a/buildSrc/build_dependencies.gradle b/buildSrc/build_dependencies.gradle
index fa04a55..7657249 100644
--- a/buildSrc/build_dependencies.gradle
+++ b/buildSrc/build_dependencies.gradle
@@ -25,8 +25,8 @@
build_versions.lint = "27.0.0-alpha01"
} else {
build_versions.kotlin = "1.3.41"
- build_versions.agp = '3.6.0-beta03'
- build_versions.lint = '26.6.0-beta03'
+ build_versions.agp = '3.6.0-beta04'
+ build_versions.lint = '26.6.0-beta04'
}
build_versions.dokka = '0.9.17-g002'
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index c6be20f..1dd08f1 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -29,7 +29,7 @@
*/
val RELEASE_RULE = docsRules("public", false) {
prebuilts(LibraryGroups.ACTIVITY, "1.1.0-rc02")
- prebuilts(LibraryGroups.ADS, "1.0.0-alpha02")
+ prebuilts(LibraryGroups.ADS, "1.0.0-alpha03")
prebuilts(LibraryGroups.ANNOTATION, "annotation", "1.1.0")
prebuilts(LibraryGroups.ANNOTATION, "annotation-experimental", "1.0.0")
prebuilts(LibraryGroups.ANNOTATION, "annotation-experimental-lint", "1.0.0")
@@ -38,9 +38,9 @@
prebuilts(LibraryGroups.ASYNCLAYOUTINFLATER, "1.0.0")
prebuilts(LibraryGroups.AUTOFILL, "1.0.0-rc01")
ignore(LibraryGroups.BENCHMARK.group, "benchmark-gradle-plugin")
- prebuilts(LibraryGroups.BENCHMARK, "1.0.0-rc01")
+ prebuilts(LibraryGroups.BENCHMARK, "1.0.0")
prebuilts(LibraryGroups.BIOMETRIC, "biometric", "1.0.0")
- prebuilts(LibraryGroups.BROWSER, "1.2.0-alpha09")
+ prebuilts(LibraryGroups.BROWSER, "1.2.0-beta01")
ignore(LibraryGroups.CAMERA.group, "camera-testing")
ignore(LibraryGroups.CAMERA.group, "camera-extensions-stub")
ignore(LibraryGroups.CAMERA.group, "camera-testlib-extensions")
@@ -63,7 +63,7 @@
prebuilts(LibraryGroups.COORDINATORLAYOUT, "1.1.0-rc01")
prebuilts(LibraryGroups.CORE, "core", "1.2.0-rc01")
prebuilts(LibraryGroups.CORE, "core-ktx", "1.2.0-rc01")
- prebuilts(LibraryGroups.CORE, "core-role", "1.0.0-alpha02")
+ prebuilts(LibraryGroups.CORE, "core-role", "1.0.0-beta01")
prebuilts(LibraryGroups.CURSORADAPTER, "1.0.0")
prebuilts(LibraryGroups.CUSTOMVIEW, "1.1.0-alpha01")
prebuilts(LibraryGroups.DOCUMENTFILE, "1.0.0")
@@ -114,7 +114,7 @@
prebuilts(LibraryGroups.RECYCLERVIEW, "recyclerview", "1.1.0")
prebuilts(LibraryGroups.RECYCLERVIEW, "recyclerview-selection", "1.1.0-alpha06")
prebuilts(LibraryGroups.REMOTECALLBACK, "1.0.0-alpha02")
- prebuilts(LibraryGroups.ROOM, "2.2.0-beta01")
+ prebuilts(LibraryGroups.ROOM, "2.2.2")
prebuilts(LibraryGroups.SAVEDSTATE, "1.0.0")
// TODO: Remove this ignore once androidx.security:security-identity-credential:1.0.0-alpha01 is released
ignore(LibraryGroups.SECURITY.group, "security-identity-credential")
@@ -138,13 +138,13 @@
prebuilts(LibraryGroups.VECTORDRAWABLE, "vectordrawable-animated", "1.1.0")
prebuilts(LibraryGroups.VERSIONEDPARCELABLE, "1.1.0")
prebuilts(LibraryGroups.VIEWPAGER, "1.0.0")
- prebuilts(LibraryGroups.VIEWPAGER2, "1.0.0-rc01")
+ prebuilts(LibraryGroups.VIEWPAGER2, "1.0.0")
prebuilts(LibraryGroups.WEAR, "1.0.0")
.addStubs("wear/wear_stubs/com.google.android.wearable-stubs.jar")
prebuilts(LibraryGroups.WEBKIT, "1.1.0")
ignore(LibraryGroups.WORK.group, "work-gcm")
ignore(LibraryGroups.WORK.group, "work-runtime-lint")
- prebuilts(LibraryGroups.WORK, "2.3.0-alpha03")
+ prebuilts(LibraryGroups.WORK, "2.3.0-beta01")
default(Ignore)
}
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index 6fb8f9e..5293510 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -110,7 +110,7 @@
internal lateinit var agpVersion: String
-const val AGP_STABLE = "com.android.tools.build:gradle:3.4.2"
+const val AGP_STABLE = "com.android.tools.build:gradle:3.5.2"
val AGP_LATEST get() = "com.android.tools.build:gradle:$agpVersion"
internal lateinit var lintVersion: String
diff --git a/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt b/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt
index c498eb4..aebc136 100644
--- a/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt
@@ -56,9 +56,9 @@
}
private object RootStudioVersions : StudioVersions() {
- override val studioVersion = "3.6.0.15"
+ override val studioVersion = "3.6.0.16"
override val ideaMajorVersion = "192"
- override val studioBuildNumber = "5982640"
+ override val studioBuildNumber = "5994180"
override val buildTxtOverride: String = ""
}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
index 69b2640..c54edb0 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
@@ -163,9 +163,8 @@
private void analyzerAnalyzesImagesWithStrategy(@BackpressureStrategy int backpressureStrategy)
throws InterruptedException {
- ImageAnalysisConfig config = new ImageAnalysisConfig.Builder().setBackpressureStrategy(
+ ImageAnalysis useCase = new ImageAnalysisConfig.Builder().setBackpressureStrategy(
backpressureStrategy).build();
- ImageAnalysis useCase = new ImageAnalysis(config);
mInstrumentation.runOnMainSync(() -> {
CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCase);
mLifecycleOwner.startAndResume();
@@ -182,8 +181,7 @@
@Test
@UiThreadTest
public void analyzerDoesNotAnalyzeImages_whenCameraIsNotOpen() throws InterruptedException {
- ImageAnalysisConfig config = new ImageAnalysisConfig.Builder().build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = new ImageAnalysisConfig.Builder().build();
// Bind but do not start lifecycle
CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCase);
useCase.setAnalyzer(CameraXExecutors.newHandlerExecutor(mHandler), mAnalyzer);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
index 19f522c..4b22f84 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
@@ -150,7 +150,7 @@
return new ImageCaptureConfig.Builder()
.setTargetRotation(surfaceRotation)
- .build();
+ .getUseCaseConfig();
}
@Before
@@ -167,9 +167,9 @@
throw new IllegalArgumentException(
"Unable to attach to camera with LensFacing " + BACK_LENS_FACING, e);
}
- mDefaultConfig = new ImageCaptureConfig.Builder().build();
+ mDefaultConfig = new ImageCaptureConfig.Builder().getUseCaseConfig();
- mFakeUseCaseConfig = new FakeUseCaseConfig.Builder().build();
+ mFakeUseCaseConfig = new FakeUseCaseConfig.Builder().getUseCaseConfig();
mRepeatingUseCase = new FakeRepeatingUseCase(mFakeUseCaseConfig, BACK_SELECTOR);
mLifecycleOwner = new FakeLifecycleOwner();
}
@@ -188,10 +188,8 @@
@Test
public void capturedImageHasCorrectSize() {
- ImageCaptureConfig config =
- new ImageCaptureConfig.Builder().setTargetResolution(
- DEFAULT_RESOLUTION).setTargetRotation(Surface.ROTATION_0).build();
- ImageCapture useCase = new ImageCapture(config);
+ ImageCapture useCase = new ImageCaptureConfig.Builder().setTargetResolution(
+ DEFAULT_RESOLUTION).setTargetRotation(Surface.ROTATION_0).build();
mInstrumentation.runOnMainSync(
() -> {
@@ -249,11 +247,9 @@
@FlakyTest //TODO(b/143734846): Callback is not always being called
@Test
public void canCaptureMultipleImagesWithMaxQuality() {
- ImageCaptureConfig config =
- new ImageCaptureConfig.Builder()
- .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
- ImageCapture useCase = new ImageCapture(config);
+ ImageCapture useCase = new ImageCaptureConfig.Builder()
+ .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
+ .build();
mInstrumentation.runOnMainSync(
() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -290,9 +286,8 @@
@Test
public void canSaveFile_withRotation() throws IOException {
- ImageCaptureConfig config =
- new ImageCaptureConfig.Builder().setTargetRotation(Surface.ROTATION_0).build();
- ImageCapture useCase = new ImageCapture(config);
+ ImageCapture useCase = new ImageCaptureConfig.Builder().setTargetRotation(
+ Surface.ROTATION_0).build();
mInstrumentation.runOnMainSync(
() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -443,7 +438,7 @@
CameraCaptureSession.CaptureCallback captureCallback =
mock(CameraCaptureSession.CaptureCallback.class);
new Camera2Config.Extender(configBuilder).setSessionCaptureCallback(captureCallback);
- ImageCapture useCase = new ImageCapture(configBuilder.build());
+ ImageCapture useCase = configBuilder.build();
mInstrumentation.runOnMainSync(
() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -483,11 +478,9 @@
Assume.assumeTrue(resolutions.length > 0);
Size resolution = resolutions[0];
- ImageCaptureConfig config =
- new ImageCaptureConfig.Builder()
- .setBufferFormat(ImageFormat.RAW10)
- .build();
- ImageCapture useCase = new ImageCapture(config);
+ ImageCapture useCase = new ImageCaptureConfig.Builder()
+ .setBufferFormat(ImageFormat.RAW10)
+ .build();
mInstrumentation.runOnMainSync(
() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -505,18 +498,15 @@
@Test(expected = IllegalArgumentException.class)
public void constructor_withBufferFormatAndCaptureProcessor_throwsException() {
- ImageCaptureConfig config =
- new ImageCaptureConfig.Builder()
- .setBufferFormat(ImageFormat.RAW_SENSOR)
- .setCaptureProcessor(mock(CaptureProcessor.class))
- .build();
- new ImageCapture(config);
+ new ImageCaptureConfig.Builder()
+ .setBufferFormat(ImageFormat.RAW_SENSOR)
+ .setCaptureProcessor(mock(CaptureProcessor.class))
+ .build();
}
@Test(expected = IllegalArgumentException.class)
public void constructor_maxCaptureStageInvalid_throwsException() {
- ImageCaptureConfig config = new ImageCaptureConfig.Builder().setMaxCaptureStages(0).build();
- new ImageCapture(config);
+ new ImageCaptureConfig.Builder().setMaxCaptureStages(0).build();
}
@Test
@@ -531,9 +521,8 @@
}
};
- ImageCaptureConfig.Builder configBuilder =
- new ImageCaptureConfig.Builder().setCaptureBundle(captureBundle);
- ImageCapture imageCapture = new ImageCapture(configBuilder.build());
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().setCaptureBundle(
+ captureBundle).build();
mInstrumentation.runOnMainSync(() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
@@ -562,12 +551,11 @@
}
};
- ImageCaptureConfig config = new ImageCaptureConfig.Builder()
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
.setMaxCaptureStages(1)
.setCaptureBundle(captureBundle)
.setCaptureProcessor(mock(CaptureProcessor.class))
.build();
- ImageCapture imageCapture = new ImageCapture(config);
mInstrumentation.runOnMainSync(() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
@@ -592,9 +580,7 @@
@Test
public void onCaptureCancelled_onErrorCAMERA_CLOSED() throws InterruptedException {
- ImageCaptureConfig config = new ImageCaptureConfig.Builder()
- .build();
- ImageCapture imageCapture = new ImageCapture(config);
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
mInstrumentation.runOnMainSync(() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
mLifecycleOwner.startAndResume();
@@ -620,9 +606,7 @@
@Test
public void onRequestFailed_OnErrorCAPTURE_FAILED() throws InterruptedException {
- ImageCaptureConfig config = new ImageCaptureConfig.Builder()
- .build();
- ImageCapture imageCapture = new ImageCapture(config);
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
mInstrumentation.runOnMainSync(() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
mLifecycleOwner.startAndResume();
@@ -651,9 +635,7 @@
@Test
public void onStateOffline_abortAllCaptureRequests() {
- ImageCaptureConfig config = new ImageCaptureConfig.Builder()
- .build();
- ImageCapture imageCapture = new ImageCapture(config);
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
mInstrumentation.runOnMainSync(() -> {
CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
mLifecycleOwner.startAndResume();
@@ -682,9 +664,7 @@
@Test
public void takePictureReturnsErrorNO_CAMERA_whenNotBound() {
- ImageCaptureConfig config = new ImageCaptureConfig.Builder()
- .build();
- ImageCapture imageCapture = new ImageCapture(config);
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
OnImageCapturedCallback callback = createMockOnImageCapturedCallback(null);
imageCapture.takePicture(mListenerExecutor, callback);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java
index 0fa883f..7bd6fe2 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java
@@ -149,7 +149,8 @@
semaphores.add(semaphore);
}
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
UseCase useCase = new UseCase(config, mReaders);
CameraUtil.openCameraWithUseCase(CAMERA_ID, mCameraInternal, useCase);
@@ -173,7 +174,8 @@
semaphores.add(semaphore);
}
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
UseCase useCase = new UseCase(config, mReaders);
CameraUtil.openCameraWithUseCase(CAMERA_ID, mCameraInternal, useCase);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
index 5221251..e7bd74c 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
@@ -38,7 +38,6 @@
import androidx.camera.core.CaptureConfig;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.core.PreviewSurfaceProviders;
import androidx.camera.core.SessionConfig;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
@@ -73,19 +72,19 @@
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
Manifest.permission.CAMERA);
- private static final Preview.PreviewSurfaceCallback MOCK_PREVIEW_SURFACE_CALLBACK =
- mock(Preview.PreviewSurfaceCallback.class);
+ private static final Preview.PreviewSurfaceProvider MOCK_PREVIEW_SURFACE_PROVIDER =
+ mock(Preview.PreviewSurfaceProvider.class);
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
- private PreviewConfig mDefaultConfig;
+ private Preview.Builder mDefaultBuilder;
private CameraSelector mCameraSelector;
private String mCameraId;
private FakeLifecycleOwner mLifecycleOwner;
private Semaphore mSurfaceFutureSemaphore;
private Semaphore mSaveToReleaseSemaphore;
- private Preview.PreviewSurfaceCallback mPreviewSurfaceCallbackWithFrameAvailableListener =
+ private Preview.PreviewSurfaceProvider mPreviewSurfaceProviderWithFrameAvailableListener =
createSurfaceTextureProvider(new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -118,7 +117,8 @@
}
// init CameraX before creating Preview to get preview size with CameraX's context
- mDefaultConfig = Preview.DEFAULT_CONFIG.getConfig(LensFacing.BACK);
+ mDefaultBuilder = Preview.Builder.fromConfig(
+ Preview.DEFAULT_CONFIG.getConfig(LensFacing.BACK));
mSurfaceFutureSemaphore = new Semaphore(/*permits=*/ 0);
mSaveToReleaseSemaphore = new Semaphore(/*permits=*/ 0);
mCameraSelector = new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
@@ -137,26 +137,26 @@
@Test
@UiThreadTest
- public void getAndSetPreviewSurfaceCallback() {
- Preview preview = new Preview(mDefaultConfig);
- preview.setPreviewSurfaceCallback(MOCK_PREVIEW_SURFACE_CALLBACK);
- assertThat(preview.getPreviewSurfaceCallback()).isEqualTo(MOCK_PREVIEW_SURFACE_CALLBACK);
+ public void getAndSetPreviewSurfaceProvider() {
+ Preview preview = mDefaultBuilder.build();
+ preview.setPreviewSurfaceProvider(MOCK_PREVIEW_SURFACE_PROVIDER);
+ assertThat(preview.getPreviewSurfaceProvider()).isEqualTo(MOCK_PREVIEW_SURFACE_PROVIDER);
}
@Test
@UiThreadTest
- public void removePreviewSurfaceCallback() {
- Preview preview = new Preview(mDefaultConfig);
- preview.setPreviewSurfaceCallback(MOCK_PREVIEW_SURFACE_CALLBACK);
- preview.setPreviewSurfaceCallback(null);
- assertThat(preview.getPreviewSurfaceCallback()).isNull();
+ public void removePreviewSurfaceProvider() {
+ Preview preview = mDefaultBuilder.build();
+ preview.setPreviewSurfaceProvider(MOCK_PREVIEW_SURFACE_PROVIDER);
+ preview.setPreviewSurfaceProvider(null);
+ assertThat(preview.getPreviewSurfaceProvider()).isNull();
}
//TODO(b/143514107): This API is being removed from preview. This test should be moved.
@Test
@UiThreadTest
public void torchModeCanBeSet() {
- Preview useCase = new Preview(mDefaultConfig);
+ Preview useCase = mDefaultBuilder.build();
CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCase);
CameraControlInternal cameraControl = getFakeCameraControl();
useCase.attachCameraControl(mCameraId, cameraControl);
@@ -169,13 +169,12 @@
@Test
public void previewDetached_onSafeToReleaseCalled() throws InterruptedException {
// Arrange.
- PreviewConfig config = new PreviewConfig.Builder().build();
- Preview preview = new Preview(config);
+ Preview preview = new Preview.Builder().build();
// Act.
mInstrumentation.runOnMainSync(() -> {
- preview.setPreviewSurfaceCallback(CameraXExecutors.mainThreadExecutor(),
- mPreviewSurfaceCallbackWithFrameAvailableListener);
+ preview.setPreviewSurfaceProvider(CameraXExecutors.mainThreadExecutor(),
+ mPreviewSurfaceProviderWithFrameAvailableListener);
CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, preview);
});
@@ -192,11 +191,11 @@
}
@Test
- public void setPreviewSurfaceCallbackBeforeBind_getsFrame() throws InterruptedException {
+ public void setPreviewSurfaceProviderBeforeBind_getsFrame() throws InterruptedException {
mInstrumentation.runOnMainSync(() -> {
// Arrange.
- Preview preview = new Preview(mDefaultConfig);
- preview.setPreviewSurfaceCallback(mPreviewSurfaceCallbackWithFrameAvailableListener);
+ Preview preview = mDefaultBuilder.build();
+ preview.setPreviewSurfaceProvider(mPreviewSurfaceProviderWithFrameAvailableListener);
// Act.
CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, preview);
@@ -207,16 +206,16 @@
assertThat(mSurfaceFutureSemaphore.tryAcquire(10, TimeUnit.SECONDS)).isTrue();
}
- @Suppress // TODO(b/143703289): Remove suppression once callback can be set after bind
+ @Suppress // TODO(b/143703289): Remove suppression once provider can be set after bind
@Test
- public void setPreviewSurfaceCallbackAfterBind_getsFrame() throws InterruptedException {
+ public void setPreviewSurfaceProviderAfterBind_getsFrame() throws InterruptedException {
mInstrumentation.runOnMainSync(() -> {
// Arrange.
- Preview preview = new Preview(mDefaultConfig);
+ Preview preview = mDefaultBuilder.build();
CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, preview);
// Act.
- preview.setPreviewSurfaceCallback(mPreviewSurfaceCallbackWithFrameAvailableListener);
+ preview.setPreviewSurfaceProvider(mPreviewSurfaceProviderWithFrameAvailableListener);
mLifecycleOwner.startAndResume();
});
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java
index b6cb6a3..cb3849b 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java
@@ -52,6 +52,7 @@
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
private LifecycleOwner mLifecycle;
SurfaceOrientedMeteringPointFactory mPointFactory;
+
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
@@ -114,12 +115,10 @@
public void createPointWithFoVUseCase_success() {
assumeTrue(CameraUtil.hasCameraWithLensFacing(LensFacing.BACK));
- ImageAnalysisConfig imageAnalysisConfig =
- new ImageAnalysisConfig.Builder()
- .setTargetAspectRatio(AspectRatio.RATIO_4_3)
- .setTargetName("ImageAnalysis")
- .build();
- ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfig);
+ ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_4_3)
+ .setTargetName("ImageAnalysis")
+ .build();
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
mInstrumentation.runOnMainSync(new Runnable() {
@@ -139,12 +138,10 @@
public void createPointWithFoVUseCase_FailedNotBound() {
assumeTrue(CameraUtil.hasCameraWithLensFacing(LensFacing.BACK));
- ImageAnalysisConfig imageAnalysisConfig =
- new ImageAnalysisConfig.Builder()
- .setTargetAspectRatio(AspectRatio.RATIO_4_3)
- .setTargetName("ImageAnalysis")
- .build();
- ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfig);
+ ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_4_3)
+ .setTargetName("ImageAnalysis")
+ .build();
// This will throw IllegalStateException.
SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java
index 1645c7f..deb6d09 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java
@@ -38,7 +38,6 @@
import androidx.camera.core.ImageCaptureConfig;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.core.PreviewSurfaceProviders;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.testing.CameraUtil;
@@ -121,7 +120,7 @@
initPreview();
initImageCapture();
mInstrumentation.runOnMainSync(() -> {
- mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+ mPreview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -208,27 +207,20 @@
}
private void initImageAnalysis() {
- ImageAnalysisConfig imageAnalysisConfig =
- new ImageAnalysisConfig.Builder()
- .setTargetName("ImageAnalysis")
- .build();
mImageAnalyzer = (image, rotationDegrees) -> {
mAnalysisResult.postValue(image.getImageInfo().getTimestamp());
image.close();
};
- mImageAnalysis = new ImageAnalysis(imageAnalysisConfig);
+ mImageAnalysis = new ImageAnalysisConfig.Builder()
+ .setTargetName("ImageAnalysis")
+ .build();
}
private void initImageCapture() {
- ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().build();
-
- mImageCapture = new ImageCapture(imageCaptureConfig);
+ mImageCapture = new ImageCaptureConfig.Builder().build();
}
private void initPreview() {
- PreviewConfig.Builder configBuilder =
- new PreviewConfig.Builder()
- .setTargetName("Preview");
- mPreview = new Preview(configBuilder.build());
+ mPreview = new Preview.Builder().setTargetName("Preview").build();
}
}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java
index 7010d1f..d4b1d81 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java
@@ -806,7 +806,7 @@
new FakeUseCaseConfig.Builder().setTargetName("UseCase");
CameraSelector selector =
new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
- TestUseCase testUseCase = new TestUseCase(configBuilder.build(), selector,
+ TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig(), selector,
mMockOnImageAvailableListener);
Map<String, Size> suggestedResolutionMap = new HashMap<>();
suggestedResolutionMap.put(mCameraId, new Size(640, 480));
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java
index 1f1d6fc..fd500bf 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java
@@ -115,7 +115,7 @@
FakeUseCaseConfig.Builder configBuilder = new FakeUseCaseConfig.Builder();
new Camera2Config.Extender(configBuilder).setDeviceStateCallback(mDeviceStateCallback);
- mConfig = configBuilder.build();
+ mConfig = configBuilder.getUseCaseConfig();
mCameraId = getCameraIdForLensFacingUnchecked(LensFacing.BACK);
mUseCase = new CallbackAttachingFakeUseCase(mConfig, mCameraId);
mUseCaseGroup.addUseCase(mUseCase);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java
index ab113ef..3b0a52d 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java
@@ -147,7 +147,7 @@
public void run() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysis useCase = new ImageAnalysis(builder.build());
+ ImageAnalysis useCase = builder.build();
CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mImageAnalyzer);
@@ -180,10 +180,9 @@
public void run() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysis useCase = new ImageAnalysis(builder.build());
+ ImageAnalysis useCase = builder.build();
- ImageAnalysisConfig config2 = new ImageAnalysisConfig.Builder().build();
- ImageAnalysis useCase2 = new ImageAnalysis(config2);
+ ImageAnalysis useCase2 = new ImageAnalysisConfig.Builder().build();
CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase, useCase2);
@@ -216,7 +215,7 @@
new Camera2Config.Extender(configBuilder)
.setDeviceStateCallback(deviceStateCallback)
.setSessionCaptureCallback(sessionCaptureCallback);
- ImageAnalysis useCase = new ImageAnalysis(configBuilder.build());
+ ImageAnalysis useCase = configBuilder.build();
CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mImageAnalyzer);
mAnalysisResult.observe(mLifecycle, createCountIncrementingObserver(observedCount));
@@ -253,8 +252,7 @@
public void bind_opensCamera() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -272,8 +270,7 @@
public void bind_opensCamera_withOutAnalyzer() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -295,8 +292,7 @@
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback)
.setSessionStateCallback(mockSessionStateCallback);
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -321,8 +317,7 @@
for (int i = 0; i < 2; i++) {
CameraDevice.StateCallback callback = mock(CameraDevice.StateCallback.class);
new Camera2Config.Extender(builder).setDeviceStateCallback(callback);
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -352,8 +347,7 @@
for (int i = 0; i < 2; i++) {
CameraDevice.StateCallback callback = mock(CameraDevice.StateCallback.class);
new Camera2Config.Extender(builder).setDeviceStateCallback(callback);
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -380,8 +374,7 @@
public void unbindAll_closesAllCameras() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -407,8 +400,7 @@
public void unbindAllAssociatedUseCase_closesCamera() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -434,14 +426,11 @@
public void unbindPartialAssociatedUseCase_doesNotCloseCamera() throws InterruptedException {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysisConfig config0 = builder.build();
- ImageAnalysis useCase0 = new ImageAnalysis(config0);
+ ImageAnalysis useCase0 = builder.build();
- ImageCaptureConfig configuration =
- new ImageCaptureConfig.Builder()
- .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
- ImageCapture useCase1 = new ImageCapture(configuration);
+ ImageCapture useCase1 = new ImageCaptureConfig.Builder()
+ .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
+ .build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -469,14 +458,11 @@
public void unbindAllAssociatedUseCaseInParts_ClosesCamera() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
- ImageAnalysisConfig config0 = builder.build();
- ImageAnalysis useCase0 = new ImageAnalysis(config0);
+ ImageAnalysis useCase0 = builder.build();
- ImageCaptureConfig configuration =
- new ImageCaptureConfig.Builder()
- .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
- ImageCapture useCase1 = new ImageCapture(configuration);
+ ImageCapture useCase1 = new ImageCaptureConfig.Builder()
+ .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
+ .build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
@@ -503,8 +489,7 @@
@UiThreadTest
public void cameraInfo_getCameraInfoFromCamera() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
Camera camera = CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
@@ -515,8 +500,7 @@
@UiThreadTest
public void cameraControl_getCameraControlFromCamera() {
ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
- ImageAnalysisConfig config = builder.build();
- ImageAnalysis useCase = new ImageAnalysis(config);
+ ImageAnalysis useCase = builder.build();
Camera camera = CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java
index a2a7616..07362fce 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java
@@ -57,7 +57,7 @@
@Test(expected = IllegalArgumentException.class)
public void failedWhenBindTooManyImageCapture() {
- ImageCaptureConfig config = new ImageCaptureConfig.Builder().build();
+ ImageCaptureConfig config = new ImageCaptureConfig.Builder().getUseCaseConfig();
ImageCapture useCase1 = new ImageCapture(config);
ImageCapture useCase2 = new ImageCapture(config);
@@ -69,7 +69,7 @@
@Test(expected = IllegalArgumentException.class)
public void failedWhenBindTooManyVideoCapture() {
- VideoCaptureConfig config = new VideoCaptureConfig.Builder().build();
+ VideoCaptureConfig config = new VideoCaptureConfig.Builder().getUseCaseConfig();
VideoCapture useCase1 = new VideoCapture(config);
VideoCapture useCase2 = new VideoCapture(config);
@@ -81,11 +81,8 @@
@Test
public void passWhenNotBindTooManyImageVideoCapture() {
- ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().build();
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfig);
-
- VideoCaptureConfig videoCaptureConfig = new VideoCaptureConfig.Builder().build();
- VideoCapture videoCapture = new VideoCapture(videoCaptureConfig);
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
+ VideoCapture videoCapture = new VideoCaptureConfig.Builder().build();
UseCaseSurfaceOccupancyManager.checkUseCaseLimitNotExceeded(
Collections.<UseCase>singletonList(imageCapture),
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java
index 9533b0b..04654d1 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java
@@ -35,6 +35,7 @@
/**
* Provides defaults for {@link ImageAnalysisConfig} in the Camera2 implementation.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY)
@@ -91,6 +92,6 @@
Log.w(TAG, "Unable to determine default lens facing for ImageAnalysis.", e);
}
- return builder.build();
+ return builder.getUseCaseConfig();
}
}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java
index dc18b1f..99b4677 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java
@@ -35,6 +35,7 @@
/**
* Provides defaults for {@link ImageCaptureConfig} in the Camera2 implementation.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY)
@@ -91,6 +92,6 @@
Log.w(TAG, "Unable to determine default lens facing for ImageCapture.", e);
}
- return builder.build();
+ return builder.getUseCaseConfig();
}
}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java
index 054fffb8..5eb1f5d 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java
@@ -35,6 +35,7 @@
/**
* Provides defaults for {@link PreviewConfig} in the Camera2 implementation.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY)
@@ -53,8 +54,8 @@
@Override
public PreviewConfig getConfig(LensFacing lensFacing) {
- PreviewConfig.Builder builder =
- PreviewConfig.Builder.fromConfig(Preview.DEFAULT_CONFIG.getConfig(lensFacing));
+ Preview.Builder builder = Preview.Builder.fromConfig(
+ Preview.DEFAULT_CONFIG.getConfig(lensFacing));
// SessionConfig containing all intrinsic properties needed for Preview
SessionConfig.Builder sessionBuilder = new SessionConfig.Builder();
@@ -89,6 +90,6 @@
Log.w(TAG, "Unable to determine default lens facing for Preview.", e);
}
- return builder.build();
+ return builder.getUseCaseConfig();
}
}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
index 918b673..c67da97 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
@@ -364,10 +364,10 @@
List<Size> sizesNotMatchAspectRatio = new ArrayList<>();
Rational aspectRatio = null;
- Integer targetAspectRatio = config.getTargetAspectRatio(null);
- if (targetAspectRatio != null) {
+ if (config.hasTargetAspectRatio()) {
// Checks the sensor orientation.
boolean isSensorLandscapeOrientation = isRotationNeeded(Surface.ROTATION_0);
+ @AspectRatio int targetAspectRatio = config.getTargetAspectRatio();
switch (targetAspectRatio) {
case AspectRatio.RATIO_4_3:
aspectRatio =
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java
index 0c5e47f..8d3eafc 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java
@@ -35,6 +35,7 @@
/**
* Provides defaults for {@link VideoCaptureConfig} in the Camera2 implementation.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY)
@@ -91,6 +92,6 @@
Log.w(TAG, "Unable to determine default lens facing for VideoCapture.", e);
}
- return builder.build();
+ return builder.getUseCaseConfig();
}
}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java
index 7a88fe74..29d4c2d 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java
@@ -62,7 +62,7 @@
.setSessionCaptureCallback(captureCallback);
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
- mUnpacker.unpack(imageCaptureConfigBuilder.build(), captureBuilder);
+ mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), captureBuilder);
CaptureConfig captureConfig = captureBuilder.build();
CameraCaptureCallback cameraCaptureCallback =
@@ -84,7 +84,7 @@
CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
- mUnpacker.unpack(imageCaptureConfigBuilder.build(), captureBuilder);
+ mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), captureBuilder);
CaptureConfig captureConfig = captureBuilder.build();
Camera2Config config = new Camera2Config(captureConfig.getImplementationOptions());
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java
index 0079028..55c1978 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java
@@ -330,17 +330,15 @@
@Test
public void suggestedResolutionsForMixedUseCaseNotSupportedInLegacyDevice() {
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
- Preview preview = new Preview(previewConfigBuilder.build());
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ Preview preview = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(imageCapture);
@@ -361,17 +359,15 @@
@Test
public void getSuggestedResolutionsForMixedUseCaseInLimitedDevice() {
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
- Preview preview = new Preview(previewConfigBuilder.build());
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ Preview preview = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(imageCapture);
@@ -389,7 +385,7 @@
@Test
public void transformSurfaceConfigWithYUVAnalysisSize() {
SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
- LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mAnalysisSize);
+ LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mAnalysisSize);
SurfaceConfig expectedSurfaceConfig =
SurfaceConfig.create(ConfigType.YUV, ConfigSize.ANALYSIS);
assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -398,7 +394,7 @@
@Test
public void transformSurfaceConfigWithYUVPreviewSize() {
SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
- LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mPreviewSize);
+ LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mPreviewSize);
SurfaceConfig expectedSurfaceConfig =
SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW);
assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -407,7 +403,7 @@
@Test
public void transformSurfaceConfigWithYUVRecordSize() {
SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
- LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mRecordSize);
+ LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mRecordSize);
SurfaceConfig expectedSurfaceConfig =
SurfaceConfig.create(ConfigType.YUV, SurfaceConfig.ConfigSize.RECORD);
assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -416,7 +412,7 @@
@Test
public void transformSurfaceConfigWithYUVMaximumSize() {
SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
- LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mMaximumSize);
+ LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mMaximumSize);
SurfaceConfig expectedSurfaceConfig =
SurfaceConfig.create(SurfaceConfig.ConfigType.YUV, ConfigSize.MAXIMUM);
assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -425,9 +421,9 @@
@Test
public void transformSurfaceConfigWithYUVNotSupportSize() {
SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
- LEGACY_CAMERA_ID,
- ImageFormat.YUV_420_888,
- new Size(mMaximumSize.getWidth() + 1, mMaximumSize.getHeight() + 1));
+ LEGACY_CAMERA_ID,
+ ImageFormat.YUV_420_888,
+ new Size(mMaximumSize.getWidth() + 1, mMaximumSize.getHeight() + 1));
SurfaceConfig expectedSurfaceConfig =
SurfaceConfig.create(ConfigType.YUV, ConfigSize.NOT_SUPPORT);
assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -501,10 +497,9 @@
mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
Rational targetAspectRatio = new Rational(9, 16);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- PreviewConfig previewConfig = previewConfigBuilder.build();
+ PreviewConfig previewConfig = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .getUseCaseConfig();
CameraDeviceConfig deviceConfig =
CameraSelectorUtil.toCameraDeviceConfig(
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java
index c742129..d544ea2 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java
@@ -73,7 +73,7 @@
.setCameraEventCallback(cameraEventCallbacks);
SessionConfig.Builder sessionBuilder = new SessionConfig.Builder();
- mUnpacker.unpack(imageCaptureConfigBuilder.build(), sessionBuilder);
+ mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), sessionBuilder);
SessionConfig sessionConfig = sessionBuilder.build();
CameraCaptureCallback interopCallback =
@@ -105,7 +105,7 @@
CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
SessionConfig.Builder sessionBuilder = new SessionConfig.Builder();
- mUnpacker.unpack(imageCaptureConfigBuilder.build(), sessionBuilder);
+ mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), sessionBuilder);
SessionConfig sessionConfig = sessionBuilder.build();
Camera2Config config = new Camera2Config(sessionConfig.getImplementationOptions());
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java
index 7a903d7..3d41e17 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java
@@ -88,7 +88,7 @@
new ConfigProvider<FakeUseCaseConfig>() {
@Override
public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
- return new FakeUseCaseConfig.Builder().build();
+ return new FakeUseCaseConfig.Builder().getUseCaseConfig();
}
});
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java
index a4deffc..a49500a 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java
@@ -92,7 +92,7 @@
@Test
public void unpackWithoutCaptureMode() {
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
- ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().build();
+ ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_API26);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -109,7 +109,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_API26);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -126,7 +126,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_API26);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -143,7 +143,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_NOT_SUPPORT_API);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -160,7 +160,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_NOT_SUPPORT_API);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -177,7 +177,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_API26);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -194,7 +194,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_API26);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -211,7 +211,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_NOT_SUPPORT_API);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -228,7 +228,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_NOT_SUPPORT_API);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -245,7 +245,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_NOT_GOOGLE);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -262,7 +262,7 @@
CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
- .build();
+ .getUseCaseConfig();
mUnpacker.setDeviceProperty(PROPERTIES_NOT_SUPPORT_MODEL);
mUnpacker.unpack(imageCaptureConfig, captureBuilder);
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java
index 5accefc..1682758 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java
@@ -477,10 +477,9 @@
mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
Rational targetAspectRatio = new Rational(9, 16);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- Preview preview = new Preview(previewConfigBuilder.build());
+ final Preview preview = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
// Ensure we are bound to a camera to ensure aspect ratio correction is applied.
FakeLifecycleOwner fakeLifecycle = new FakeLifecycleOwner();
@@ -526,13 +525,9 @@
new SupportedSurfaceCombination(
mContext, LIMITED_CAMERA_ID, mMockCamcorderProfileHelper);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
- ImageAnalysisConfig.Builder imageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
-
- Preview preview = new Preview(previewConfigBuilder.build());
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfigBuilder.build());
+ Preview preview = new Preview.Builder().build();
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
+ ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder().build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(preview);
@@ -564,10 +559,10 @@
public void checkDefaultLensFacingForMixedUseCase() {
setupCamera(/* supportsRaw= */ false);
- Preview preview = new Preview(new PreviewConfig.Builder().build());
- ImageCapture imageCapture = new ImageCapture(new ImageCaptureConfig.Builder().build());
- ImageAnalysis imageAnalysis = new ImageAnalysis(new ImageAnalysisConfig.Builder().build());
- VideoCapture videoCapture = new VideoCapture(new VideoCaptureConfig.Builder().build());
+ Preview preview = new Preview.Builder().build();
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
+ ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder().build();
+ VideoCapture videoCapture = new VideoCaptureConfig.Builder().build();
PreviewConfig previewConfig = (PreviewConfig) preview.getUseCaseConfig();
ImageCaptureConfig imageCaptureConfig =
@@ -603,9 +598,9 @@
*/
final int displayWidth = 1080;
final int displayHeight = 2220;
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- previewConfigBuilder.setTargetResolution(new Size(displayHeight, displayWidth));
- Preview preview = new Preview(previewConfigBuilder.build());
+ Preview preview = new Preview.Builder()
+ .setTargetResolution(new Size(displayHeight, displayWidth))
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(preview);
@@ -637,9 +632,9 @@
// The resolution selection will filter out the sizes which are smaller than min(640x480,
// TARGET_RESOLUTION)
final Size targetResolution = new Size(240, 320);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- previewConfigBuilder.setTargetResolution(targetResolution);
- Preview preview = new Preview(previewConfigBuilder.build());
+ Preview preview = new Preview.Builder()
+ .setTargetResolution(targetResolution)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(preview);
@@ -660,17 +655,15 @@
new SupportedSurfaceCombination(
mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
- Preview preview = new Preview(previewConfigBuilder.build());
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ Preview preview = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(imageCapture);
@@ -689,17 +682,15 @@
new SupportedSurfaceCombination(
mContext, LIMITED_CAMERA_ID, mMockCamcorderProfileHelper);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
- Preview preview = new Preview(previewConfigBuilder.build());
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ Preview preview = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(imageCapture);
@@ -727,16 +718,15 @@
2. supportedOutputSizes for ImageCapture and Preview in
SupportedSurfaceCombination#getAllPossibleSizeArrangements are the same.
*/
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- ImageAnalysisConfig.Builder imageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
-
- imageCaptureConfigBuilder.setTargetResolution(mDisplaySize);
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- previewConfigBuilder.setTargetResolution(mDisplaySize);
- Preview preview = new Preview(previewConfigBuilder.build());
- imageAnalysisConfigBuilder.setTargetResolution(mDisplaySize);
- ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfigBuilder.build());
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setTargetResolution(mDisplaySize)
+ .build();
+ Preview preview = new Preview.Builder()
+ .setTargetResolution(mDisplaySize)
+ .build();
+ ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+ .setTargetResolution(mDisplaySize)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(imageCapture);
@@ -757,17 +747,15 @@
new SupportedSurfaceCombination(
mContext, FULL_CAMERA_ID, mMockCamcorderProfileHelper);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
- ImageAnalysisConfig.Builder imageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- imageAnalysisConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
- Preview preview = new Preview(previewConfigBuilder.build());
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfigBuilder.build());
+ Preview preview = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
+ ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(imageCapture);
@@ -796,11 +784,11 @@
setupCamera(/* supportsRaw= */ false);
boolean previewExceptionHappened = false;
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder()
+ Preview.Builder previewBuilder = new Preview.Builder()
.setTargetResolution(mDisplaySize)
.setTargetAspectRatio(AspectRatio.RATIO_16_9);
try {
- previewConfigBuilder.build();
+ previewBuilder.build();
} catch (IllegalArgumentException e) {
previewExceptionHappened = true;
}
@@ -836,24 +824,22 @@
new SupportedSurfaceCombination(
mContext, LIMITED_CAMERA_ID, mMockCamcorderProfileHelper);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
List<Pair<Integer, Size[]>> formatResolutionsPairList = new ArrayList<>();
formatResolutionsPairList.add(Pair.create(ImageFormat.JPEG, new Size[]{mAnalysisSize}));
formatResolutionsPairList.add(
Pair.create(ImageFormat.YUV_420_888, new Size[]{mAnalysisSize}));
formatResolutionsPairList.add(Pair.create(ImageFormat.PRIVATE, new Size[]{mAnalysisSize}));
- // Sets customized supported resolutions to 640x480 only.
- imageCaptureConfigBuilder.setSupportedResolutions(formatResolutionsPairList);
- videoCaptureConfigBuilder.setSupportedResolutions(formatResolutionsPairList);
- previewConfigBuilder.setSupportedResolutions(formatResolutionsPairList);
-
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
- VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
- Preview preview = new Preview(previewConfigBuilder.build());
+ // Sets use cases customized supported resolutions to 640x480 only.
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setSupportedResolutions(formatResolutionsPairList)
+ .build();
+ VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+ .setSupportedResolutions(formatResolutionsPairList)
+ .build();
+ Preview preview = new Preview.Builder()
+ .setSupportedResolutions(formatResolutionsPairList)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(imageCapture);
@@ -1031,17 +1017,14 @@
new SupportedSurfaceCombination(
mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
- ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
- previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
- imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
- previewConfigBuilder.setDefaultResolution(mMod16Size);
- imageCaptureConfigBuilder.setDefaultResolution(mMod16Size);
-
- Preview preview = new Preview(previewConfigBuilder.build());
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
+ Preview preview = new Preview.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .setDefaultResolution(mMod16Size)
+ .build();
+ ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+ .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+ .setDefaultResolution(mMod16Size)
+ .build();
List<UseCase> useCases = new ArrayList<>();
useCases.add(preview);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
index c728aeb..0ec35f7 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
@@ -85,7 +85,7 @@
new ConfigProvider<FakeUseCaseConfig>() {
@Override
public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
- return new FakeUseCaseConfig.Builder().build();
+ return new FakeUseCaseConfig.Builder().getUseCaseConfig();
}
});
mUseCaseConfigFactory = defaultConfigFactory;
@@ -224,12 +224,9 @@
@UiThreadTest
public void bindMultipleUseCases() {
initCameraX();
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().setTargetName("config0").build();
- FakeUseCase fakeUseCase = new FakeUseCase(config0);
- FakeOtherUseCaseConfig config1 =
- new FakeOtherUseCaseConfig.Builder().setTargetName("config1").build();
- FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCase(config1);
+ FakeUseCase fakeUseCase = new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+ FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCaseConfig.Builder().setTargetName(
+ "config1").build();
CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase, fakeOtherUseCase);
@@ -252,14 +249,12 @@
@UiThreadTest
public void bind_createsDifferentUseCaseGroups_forDifferentLifecycles() {
initCameraX();
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().setTargetName("config0").build();
- CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, new FakeUseCase(config0));
+ CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR,
+ new FakeUseCaseConfig.Builder().setTargetName("config0").build());
- FakeUseCaseConfig config1 =
- new FakeUseCaseConfig.Builder().setTargetName("config1").build();
FakeLifecycleOwner anotherLifecycle = new FakeLifecycleOwner();
- CameraX.bindToLifecycle(anotherLifecycle, CAMERA_SELECTOR, new FakeUseCase(config1));
+ CameraX.bindToLifecycle(anotherLifecycle, CAMERA_SELECTOR,
+ new FakeUseCaseConfig.Builder().setTargetName("config1").build());
// One observer is the use case group. The other observer removes the use case upon the
// lifecycle's destruction.
@@ -309,14 +304,10 @@
CameraSelector frontSelector =
new CameraSelector.Builder().requireLensFacing(LensFacing.FRONT).build();
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().build();
- FakeUseCase fakeUseCase = new FakeUseCase(config0);
+ FakeUseCase fakeUseCase = new FakeUseCaseConfig.Builder().build();
CameraSelector backSelector =
new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
- FakeOtherUseCaseConfig config1 =
- new FakeOtherUseCaseConfig.Builder().build();
- FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCase(config1);
+ FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCaseConfig.Builder().build();
boolean hasException = false;
try {
@@ -331,7 +322,7 @@
@UiThreadTest
public void bindUseCases_successReturnCamera() {
initCameraX();
- FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().build();
+ FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().getUseCaseConfig();
assertThat(CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR,
new FakeUseCase(config0))).isInstanceOf(Camera.class);
@@ -343,7 +334,7 @@
initCameraX();
CameraSelector frontSelector = new CameraSelector.Builder().requireLensFacing(
LensFacing.FRONT).build();
- FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().build();
+ FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().getUseCaseConfig();
FakeUseCase fakeUseCase = new FakeUseCase(config0);
// The front camera is not defined, we should get the IllegalArgumentException when it
@@ -365,8 +356,8 @@
@UiThreadTest
public void attachCameraControl_afterBindToLifecycle() {
initCameraX();
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+ FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+ "config0").getUseCaseConfig();
AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(config0);
CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
@@ -379,8 +370,8 @@
@UiThreadTest
public void onCameraControlReadyIsCalled_afterBindToLifecycle() {
initCameraX();
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+ FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+ "config0").getUseCaseConfig();
AttachCameraFakeCase fakeUseCase = spy(new AttachCameraFakeCase(config0));
CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
@@ -392,8 +383,8 @@
@UiThreadTest
public void detachCameraControl_afterUnbind() {
initCameraX();
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+ FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+ "config0").getUseCaseConfig();
AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(config0);
CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
@@ -415,7 +406,8 @@
FakeUseCaseConfig.Builder fakeConfigBuilder = new FakeUseCaseConfig.Builder();
fakeConfigBuilder.setUseCaseEventCallback(eventCallback);
- AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(fakeConfigBuilder.build());
+ AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(
+ fakeConfigBuilder.getUseCaseConfig());
CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
Mockito.verify(eventCallback).onBind(mCameraId);
@@ -444,12 +436,9 @@
@UiThreadTest
public void canGetActiveUseCases_afterBindToLifecycle() {
initCameraX();
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().setTargetName("config0").build();
- FakeUseCase fakeUseCase = new FakeUseCase(config0);
- FakeOtherUseCaseConfig config1 =
- new FakeOtherUseCaseConfig.Builder().setTargetName("config1").build();
- FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCase(config1);
+ FakeUseCase fakeUseCase = new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+ FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCaseConfig.Builder().setTargetName(
+ "config1").build();
CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase, fakeOtherUseCase);
mLifecycle.startAndResume();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
index 7aed7d0..e1f1d54 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
@@ -39,7 +39,7 @@
/** Creates a new instance of a {@link FakeOtherUseCase} with a default configuration. */
FakeOtherUseCase() {
- this(new FakeOtherUseCaseConfig.Builder().build());
+ this(new FakeOtherUseCaseConfig.Builder().getUseCaseConfig());
}
@Override
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java
index 007be6e..eb5f67b 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java
@@ -252,10 +252,16 @@
return mOptionsBundle;
}
+ @NonNull
+ @Override
+ public FakeOtherUseCaseConfig getUseCaseConfig() {
+ return new FakeOtherUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+ }
+
@Override
@NonNull
- public FakeOtherUseCaseConfig build() {
- return new FakeOtherUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+ public FakeOtherUseCase build() {
+ return new FakeOtherUseCase(getUseCaseConfig());
}
// Implementations of TargetConfig.Builder default methods
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java
index d7e7435..51f196e 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java
@@ -111,8 +111,8 @@
}
@Override
- public void onError(
- SaveError saveError, String message, @Nullable Throwable cause) {
+ public void onError(@SaveError int saveError, String message,
+ @Nullable Throwable cause) {
mMockCallback.onError(saveError, message, cause);
mSemaphore.release();
}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java
index 9c6612b..768a9e4 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java
@@ -51,9 +51,9 @@
@RunWith(AndroidJUnit4.class)
public class UseCaseAttachStateTest {
private static final CameraSelector BACK_CAMERA_SELECTOR =
- new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
+ new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
private static final CameraSelector FRONT_CAMERA_SELECTOR =
- new CameraSelector.Builder().requireLensFacing(LensFacing.FRONT).build();
+ new CameraSelector.Builder().requireLensFacing(LensFacing.FRONT).build();
private final CameraDevice mMockCameraDevice = Mockito.mock(CameraDevice.class);
private final CameraCaptureSession mMockCameraCaptureSession =
Mockito.mock(CameraCaptureSession.class);
@@ -84,7 +84,7 @@
FakeUseCaseConfig config =
new FakeUseCaseConfig.Builder()
.setTargetName("UseCase")
- .build();
+ .getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -114,11 +114,11 @@
@Test
public void setTwoUseCasesOnline() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config0 =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase0 = new TestUseCase(config0, BACK_CAMERA_SELECTOR, mCameraId);
- FakeUseCaseConfig config1 =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config1 = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase1 = new TestUseCase(config1, BACK_CAMERA_SELECTOR, mCameraId);
useCaseAttachState.setUseCaseOnline(fakeUseCase0);
@@ -154,8 +154,8 @@
@Test
public void setUseCaseActiveOnly() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
useCaseAttachState.setUseCaseActive(fakeUseCase);
@@ -184,8 +184,8 @@
@Test
public void setUseCaseActiveAndOnline() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -216,8 +216,8 @@
@Test
public void setUseCaseOffline() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -247,8 +247,8 @@
@Test
public void setUseCaseInactive() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -279,8 +279,8 @@
@Test
public void updateUseCase() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -306,8 +306,8 @@
@Test(expected = IllegalArgumentException.class)
public void setUseCaseOnlineWithWrongCamera() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, FRONT_CAMERA_SELECTOR, mCameraId);
@@ -318,8 +318,8 @@
@Test(expected = IllegalArgumentException.class)
public void setUseCaseActiveWithWrongCamera() {
UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
- FakeUseCaseConfig config =
- new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase fakeUseCase = new TestUseCase(config, FRONT_CAMERA_SELECTOR, mCameraId);
// Should throw IllegalArgumentException
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java
index 664f066..cbeda0a 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java
@@ -45,11 +45,11 @@
public void setUp() {
FakeUseCaseConfig fakeUseCaseConfig = new FakeUseCaseConfig.Builder()
.setTargetName("fakeUseCaseConfig")
- .build();
+ .getUseCaseConfig();
FakeOtherUseCaseConfig fakeOtherUseCaseConfig =
new FakeOtherUseCaseConfig.Builder()
.setTargetName("fakeOtherUseCaseConfig")
- .build();
+ .getUseCaseConfig();
mUseCaseGroup = new UseCaseGroup();
mFakeUseCase = new FakeUseCase(fakeUseCaseConfig);
mFakeOtherUseCase = new FakeOtherUseCase(fakeOtherUseCaseConfig);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
index d373c97..3dbcbb9 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
@@ -51,7 +51,8 @@
@Test
public void getAttachedCamera() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
SessionConfig sessionToAttach = new SessionConfig.Builder().build();
testUseCase.attachToCamera("Camera", sessionToAttach);
@@ -63,7 +64,8 @@
@Test
public void getAttachedSessionConfig() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
SessionConfig sessionToAttach = new SessionConfig.Builder().build();
testUseCase.attachToCamera("Camera", sessionToAttach);
@@ -75,7 +77,8 @@
@Test
public void removeListener() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
testUseCase.addStateChangeCallback(mMockUseCaseCallback);
testUseCase.removeStateChangeCallback(mMockUseCaseCallback);
@@ -87,7 +90,8 @@
@Test
public void clearListeners() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
testUseCase.addStateChangeCallback(mMockUseCaseCallback);
testUseCase.clear();
@@ -98,7 +102,8 @@
@Test
public void notifyActiveState() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
testUseCase.addStateChangeCallback(mMockUseCaseCallback);
@@ -108,7 +113,8 @@
@Test
public void notifyInactiveState() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
testUseCase.addStateChangeCallback(mMockUseCaseCallback);
@@ -118,7 +124,8 @@
@Test
public void notifyUpdatedSettings() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
testUseCase.addStateChangeCallback(mMockUseCaseCallback);
@@ -128,7 +135,8 @@
@Test
public void notifyResetUseCase() {
- FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+ FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+ "UseCase").getUseCaseConfig();
TestUseCase testUseCase = new TestUseCase(config);
testUseCase.addStateChangeCallback(mMockUseCaseCallback);
@@ -142,7 +150,7 @@
FakeUseCaseConfig.Builder configBuilder =
new FakeUseCaseConfig.Builder().setTargetName(originalName);
- TestUseCase testUseCase = new TestUseCase(configBuilder.build());
+ TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig());
String originalRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
// NOTE: Updating the use case name is probably a very bad idea in most cases. However,
@@ -150,7 +158,7 @@
// it here for the sake of this test.
String newName = "UseCase-New";
configBuilder.setTargetName(newName);
- testUseCase.updateUseCaseConfig(configBuilder.build());
+ testUseCase.updateUseCaseConfig(configBuilder.getUseCaseConfig());
String newRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
assertThat(originalRetrievedName).isEqualTo(originalName);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java b/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java
index 210ce14..6011859 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java
@@ -20,6 +20,7 @@
import android.view.Surface;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.camera.core.impl.utils.futures.Futures;
import androidx.concurrent.futures.CallbackToFutureAdapter;
@@ -28,30 +29,32 @@
import java.util.concurrent.Executor;
/**
- * A {@link DeferrableSurface} wraps around user provided {@link Preview.PreviewSurfaceCallback}
+ * A {@link DeferrableSurface} wraps around user provided {@link Preview.PreviewSurfaceProvider}
* and {@link Executor}.
*/
final class CallbackDeferrableSurface extends DeferrableSurface implements SurfaceHolder {
@NonNull
private ListenableFuture<Surface> mSurfaceFuture;
- @NonNull
- private Preview.PreviewSurfaceCallback mPreviewSurfaceCallback;
+ @Nullable
+ private CallbackToFutureAdapter.Completer<Void> mCancellationCompleter;
@NonNull
private Executor mCallbackExecutor;
CallbackDeferrableSurface(@NonNull Size resolution, @NonNull Executor callbackExecutor,
- @NonNull Preview.PreviewSurfaceCallback previewSurfaceCallback) {
+ @NonNull Preview.PreviewSurfaceProvider previewSurfaceProvider) {
mCallbackExecutor = callbackExecutor;
- mPreviewSurfaceCallback = previewSurfaceCallback;
// Re-wrap user's ListenableFuture with user's executor.
mSurfaceFuture = CallbackToFutureAdapter.getFuture(
completer -> {
- callbackExecutor.execute(() -> {
- Futures.propagate(previewSurfaceCallback.createSurfaceFuture(resolution),
- completer);
-
- });
+ callbackExecutor.execute(() -> Futures.propagate(
+ previewSurfaceProvider.provideSurface(resolution,
+ CallbackToFutureAdapter.getFuture(
+ cancellationCompleter -> {
+ mCancellationCompleter = cancellationCompleter;
+ return "SurfaceCancellationFuture";
+ })),
+ completer));
return "GetSurfaceFutureWithExecutor";
});
}
@@ -66,7 +69,10 @@
*/
@Override
public void release() {
- setOnSurfaceDetachedListener(mCallbackExecutor,
- () -> mPreviewSurfaceCallback.onSafeToRelease(mSurfaceFuture));
+ setOnSurfaceDetachedListener(mCallbackExecutor, () -> {
+ if (mCancellationCompleter != null) {
+ mCancellationCompleter.set(null);
+ }
+ });
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index 0f60030d..0427339 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -138,6 +138,7 @@
// TODO(b/143915543): Ensure this never gets called by a camera that is not bound
// to this use case so we don't need to do this check.
if (isCurrentlyBoundCamera(cameraId)) {
+ // Only reset the pipeline when the bound camera is the same.
SessionConfig.Builder sessionConfigBuilder = createPipeline(cameraId, config,
resolution);
attachToCamera(cameraId, sessionConfigBuilder.build());
@@ -194,19 +195,26 @@
* Sets the target rotation.
*
* <p>This informs the use case so it can adjust the rotation value sent to
- * {@link Analyzer#analyze(ImageProxy, int)}.
- *
- * <p>In most cases this should be set to the current rotation returned by {@link
- * Display#getRotation()}. In that case, the rotation parameter sent to the analyzer will be
- * the rotation, which if applied to the output image, will make the image match the display
- * orientation.
+ * {@link Analyzer#analyze(ImageProxy, int)} which provides rotation information to the
+ * analysis method. The rotation parameter sent to the analyzer will be the rotation, which if
+ * applied to the output image, will make the image match target rotation specified here.
*
* <p>While rotation can also be set via
* {@link ImageAnalysisConfig.Builder#setTargetRotation(int)}, using
* {@link ImageAnalysis#setTargetRotation(int)} allows the target rotation to be set
- * dynamically. This can be useful if an app locks itself to portrait, and uses the orientation
- * sensor to set rotation, to process landscape images when the device is rotated by examining
- * the rotation received by the Analyzer function.
+ * dynamically.
+ *
+ * <p>In general, it is best to use an {@link android.view.OrientationEventListener} to
+ * set the target rotation. This way, the rotation output to the Analyzer will indicate
+ * which way is down for a given image. This is important since display orientation may be
+ * locked by device default, user setting, or app configuration,
+ * and some devices may not transition to a reverse-portrait display orientation. In
+ * these cases, use {@link androidx.camera.core.ImageAnalysis#setTargetRotation} to set
+ * target rotation dynamically according to the
+ * {@link android.view.OrientationEventListener}, without re-creating the use case. Note
+ * the OrientationEventListener output of degrees in the range [0..359] should be converted to
+ * a surface rotation, i.e. one of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
+ * {@link Surface#ROTATION_180}, or {@link Surface#ROTATION_270}.
*
* <p>If not set here or by configuration, the target rotation will default to the value of
* {@link Display#getRotation()} of the default display at the time the
@@ -221,7 +229,7 @@
int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != rotation) {
mUseCaseConfigBuilder.setTargetRotation(rotation);
- updateUseCaseConfig(mUseCaseConfigBuilder.build());
+ updateUseCaseConfig(mUseCaseConfigBuilder.getUseCaseConfig());
// TODO(b/122846516): Update session configuration and possibly reconfigure session.
// For now we'll just update the relative rotation value.
@@ -475,7 +483,7 @@
.setMaxResolution(DEFAULT_MAX_RESOLUTION)
.setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
- DEFAULT_CONFIG = builder.build();
+ DEFAULT_CONFIG = builder.getUseCaseConfig();
}
@Override
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
index 9157ece..de69069 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
@@ -20,7 +20,6 @@
import android.util.Pair;
import android.util.Rational;
import android.util.Size;
-import android.view.Display;
import android.view.Surface;
import androidx.annotation.NonNull;
@@ -320,17 +319,9 @@
return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
}
- /**
- * Retrieves the aspect ratio of the target intending to use images from this configuration.
- *
- * @param valueIfMissing The value to return if this configuration option has not been set.
- * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
- * configuration.
- */
- @Nullable
@Override
- public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
- return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+ public boolean hasTargetAspectRatio() {
+ return containsOption(OPTION_TARGET_ASPECT_RATIO);
}
/**
@@ -698,6 +689,18 @@
}
/**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public ImageAnalysisConfig getUseCaseConfig() {
+ return new ImageAnalysisConfig(OptionsBundle.from(mMutableConfig));
+ }
+
+ /**
* Builds an immutable {@link ImageAnalysisConfig} from the current state.
*
* @return A {@link ImageAnalysisConfig} populated with the current state.
@@ -706,7 +709,7 @@
*/
@Override
@NonNull
- public ImageAnalysisConfig build() {
+ public ImageAnalysis build() {
// Error at runtime for using both setTargetResolution and setTargetAspectRatio on
// the same config.
if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
@@ -715,7 +718,7 @@
"Cannot use both setTargetResolution and setTargetAspectRatio on the same"
+ " config.");
}
- return new ImageAnalysisConfig(OptionsBundle.from(mMutableConfig));
+ return new ImageAnalysis(getUseCaseConfig());
}
// Implementations of TargetConfig.Builder default methods
@@ -737,7 +740,7 @@
}
/**
- * Sets the name of the target object being configured.
+ * Sets the name of the target object being configured, used only for debug logging.
*
* <p>The name should be a value that can uniquely identify an instance of the object being
* configured.
@@ -857,12 +860,24 @@
/**
* Sets the rotation of the intended target for images from this configuration.
*
+ * <p>The rotation parameter sent to the analyzer will be the rotation, which if applied to
+ * the output image, will make the image match target rotation specified here.
+ *
* <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link
* Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
* Rotation values are relative to the "natural" rotation, {@link Surface#ROTATION_0}.
*
+ * <p>In general, it is best to additionally set the target rotation dynamically on the use
+ * case. See
+ * {@link androidx.camera.core.ImageAnalysis#setTargetRotation(int)} for additional
+ * documentation.
+ *
* <p>If not set, the target rotation will default to the value of
- * {@link Display#getRotation()} of the default display at the time the use case is created.
+ * {@link android.view.Display#getRotation()} of the default display at the time the
+ * use case is created.
+ *
+ * @see androidx.camera.core.ImageAnalysis#setTargetRotation(int)
+ * @see android.view.OrientationEventListener
*
* @param rotation The rotation of the intended target.
* @return The current Builder.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 0c1d084..e04242e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -282,6 +282,7 @@
// TODO(b/143915543): Ensure this never gets called by a camera that is not bound
// to this use case so we don't need to do this check.
if (isCurrentlyBoundCamera(cameraId)) {
+ // Only reset the pipeline when the bound camera is the same.
mSessionConfigBuilder = createPipeline(cameraId, config, resolution);
attachToCamera(cameraId, mSessionConfigBuilder.build());
notifyReset();
@@ -399,7 +400,7 @@
Rational oldRatio = oldConfig.getTargetAspectRatioCustom(null);
if (!aspectRatio.equals(oldRatio)) {
mUseCaseConfigBuilder.setTargetAspectRatioCustom(aspectRatio);
- updateUseCaseConfig(mUseCaseConfigBuilder.build());
+ updateUseCaseConfig(mUseCaseConfigBuilder.getUseCaseConfig());
mConfig = (ImageCaptureConfig) getUseCaseConfig();
// TODO(b/122846516): Reconfigure capture session if the ratio is changed drastically.
@@ -446,7 +447,7 @@
int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != rotation) {
mUseCaseConfigBuilder.setTargetRotation(rotation);
- updateUseCaseConfig(mUseCaseConfigBuilder.build());
+ updateUseCaseConfig(mUseCaseConfigBuilder.build().getUseCaseConfig());
mConfig = (ImageCaptureConfig) getUseCaseConfig();
// TODO(b/122846516): Update session configuration and possibly reconfigure session.
@@ -542,11 +543,11 @@
}
@Override
- public void onError(ImageSaver.SaveError error, String message,
+ public void onError(@ImageSaver.SaveError int error, String message,
@Nullable Throwable cause) {
@ImageCaptureError int imageCaptureError = ImageCaptureError.UNKNOWN_ERROR;
switch (error) {
- case FILE_IO_FAILED:
+ case ImageSaver.SaveError.FILE_IO_FAILED:
imageCaptureError = ImageCaptureError.FILE_IO_ERROR;
break;
default:
@@ -1208,7 +1209,7 @@
.setFlashMode(DEFAULT_FLASH_MODE)
.setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
- DEFAULT_CONFIG = builder.build();
+ DEFAULT_CONFIG = builder.getUseCaseConfig();
}
@Override
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
index 8b9f468..fc6971c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
@@ -94,18 +94,6 @@
/**
* Returns the {@link FlashMode}.
*
- * @param valueIfMissing The value to return if this configuration option has not been set.
- * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
- * configuration.
- */
- @Nullable
- public Integer getFlashMode(@Nullable Integer valueIfMissing) {
- return retrieveOption(OPTION_FLASH_MODE, valueIfMissing);
- }
-
- /**
- * Returns the {@link FlashMode}.
- *
* @return The stored value, if it exists in this configuration.
* @throws IllegalArgumentException if the option does not exist in this configuration.
*/
@@ -422,17 +410,9 @@
return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
}
- /**
- * Retrieves the aspect ratio of the target intending to use images from this configuration.
- *
- * @param valueIfMissing The value to return if this configuration option has not been set.
- * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
- * configuration.
- */
- @Nullable
@Override
- public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
- return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+ public boolean hasTargetAspectRatio() {
+ return containsOption(OPTION_TARGET_ASPECT_RATIO);
}
/**
@@ -763,15 +743,27 @@
}
/**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public ImageCaptureConfig getUseCaseConfig() {
+ return new ImageCaptureConfig(OptionsBundle.from(mMutableConfig));
+ }
+
+ /**
* Builds an immutable {@link ImageCaptureConfig} from the current state.
*
* @return A {@link ImageCaptureConfig} populated with the current state.
* @throws IllegalArgumentException if attempting to set both target aspect ratio and
- * target resolution.
+ * target resolution.
*/
@Override
@NonNull
- public ImageCaptureConfig build() {
+ public ImageCapture build() {
// Error at runtime for using both setTargetResolution and setTargetAspectRatio on
// the same config.
if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
@@ -780,7 +772,7 @@
"Cannot use both setTargetResolution and setTargetAspectRatio on the same "
+ "config.");
}
- return new ImageCaptureConfig(OptionsBundle.from(mMutableConfig));
+ return new ImageCapture(getUseCaseConfig());
}
/**
@@ -908,7 +900,7 @@
}
/**
- * Sets the name of the target object being configured.
+ * Sets the name of the target object being configured, used only for debug logging.
*
* <p>The name should be a value that can uniquely identify an instance of the object being
* configured.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
index 3951792..68431fa 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
@@ -144,14 +144,12 @@
Rational getTargetAspectRatioCustom();
/**
- * Retrieves the aspect ratio of the target intending to use images from this configuration.
+ * Verifies whether the aspect ratio of the target intending to use images from this
+ * configuration is set.
*
- * @param valueIfMissing The value to return if this configuration option has not been set.
- * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
- * configuration.
+ * @return true is the value exists in this configuration, false otherwise.
*/
- @Nullable
- Integer getTargetAspectRatio(@Nullable Integer valueIfMissing);
+ boolean hasTargetAspectRatio();
/**
* Retrieves the aspect ratio of the target intending to use images from this configuration.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java
index 0648e8d..8500ce9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java
@@ -18,12 +18,15 @@
import android.location.Location;
+import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.camera.core.ImageUtil.CodecFailedException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
final class ImageSaver implements Runnable {
@@ -68,7 +71,7 @@
@Override
public void run() {
// Finally, we save the file to disk
- SaveError saveError = null;
+ Integer saveError = null;
String errorMessage = null;
Exception exception = null;
try (ImageProxy imageToClose = mImage;
@@ -128,7 +131,7 @@
});
}
- private void postError(final SaveError saveError, final String message,
+ private void postError(final @SaveError int saveError, final String message,
@Nullable final Throwable cause) {
mExecutor.execute(new Runnable() {
@Override
@@ -139,20 +142,23 @@
}
/** Type of error that occurred during save */
- public enum SaveError {
+ @IntDef({SaveError.FILE_IO_FAILED, SaveError.ENCODE_FAILED, SaveError.CROP_FAILED,
+ SaveError.UNKNOWN})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SaveError {
/** Failed to write to or close the file */
- FILE_IO_FAILED,
+ int FILE_IO_FAILED = 0;
/** Failure when attempting to encode image */
- ENCODE_FAILED,
+ int ENCODE_FAILED = 1;
/** Failure when attempting to crop image */
- CROP_FAILED,
- UNKNOWN
+ int CROP_FAILED = 2;
+ int UNKNOWN = 3;
}
public interface OnImageSavedCallback {
void onImageSaved(File file);
- void onError(SaveError saveError, String message, @Nullable Throwable cause);
+ void onError(@SaveError int saveError, String message, @Nullable Throwable cause);
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index c36070a..e60878f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -16,14 +16,37 @@
package androidx.camera.core;
+import static androidx.camera.core.PreviewConfig.IMAGE_INFO_PROCESSOR;
+import static androidx.camera.core.PreviewConfig.OPTION_BACKGROUND_EXECUTOR;
+import static androidx.camera.core.PreviewConfig.OPTION_CAMERA_ID_FILTER;
+import static androidx.camera.core.PreviewConfig.OPTION_CAPTURE_CONFIG_UNPACKER;
+import static androidx.camera.core.PreviewConfig.OPTION_DEFAULT_CAPTURE_CONFIG;
+import static androidx.camera.core.PreviewConfig.OPTION_DEFAULT_RESOLUTION;
+import static androidx.camera.core.PreviewConfig.OPTION_DEFAULT_SESSION_CONFIG;
+import static androidx.camera.core.PreviewConfig.OPTION_LENS_FACING;
+import static androidx.camera.core.PreviewConfig.OPTION_MAX_RESOLUTION;
+import static androidx.camera.core.PreviewConfig.OPTION_PREVIEW_CAPTURE_PROCESSOR;
+import static androidx.camera.core.PreviewConfig.OPTION_SESSION_CONFIG_UNPACKER;
+import static androidx.camera.core.PreviewConfig.OPTION_SUPPORTED_RESOLUTIONS;
+import static androidx.camera.core.PreviewConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_ASPECT_RATIO;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_ASPECT_RATIO_CUSTOM;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_CLASS;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_NAME;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_RESOLUTION;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_ROTATION;
+import static androidx.camera.core.PreviewConfig.OPTION_USE_CASE_EVENT_CALLBACK;
+
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.media.ImageReader;
import android.media.MediaCodec;
import android.os.Handler;
import android.os.HandlerThread;
+import android.util.Pair;
import android.util.Rational;
import android.util.Size;
+import android.view.Display;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.TextureView;
@@ -36,19 +59,20 @@
import androidx.annotation.UiThread;
import androidx.camera.core.impl.utils.Threads;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.core.util.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.Executor;
/**
* A use case that provides a camera preview stream for displaying on-screen.
*
* <p>The preview stream is connected to the {@link Surface} provided via
- * {@link PreviewSurfaceCallback}. The application decides how the {@link Surface} is shown,
+ * {@link PreviewSurfaceProvider}. The application decides how the {@link Surface} is shown,
* and is responsible for managing the {@link Surface} lifecycle after providing it.
*
* <p> To display the preview with the correct orientation, app needs to take different actions
@@ -103,10 +127,10 @@
@SuppressWarnings("WeakerAccess") /* synthetic accessor */
@Nullable
- PreviewSurfaceCallback mPreviewSurfaceCallback;
+ PreviewSurfaceProvider mPreviewSurfaceProvider;
@SuppressWarnings("WeakerAccess") /* Synthetic Accessor */
@Nullable
- Executor mPreviewSurfaceCallbackExecutor;
+ Executor mPreviewSurfaceProviderExecutor;
// Cached latest resolution for creating the pipeline as soon as it's ready.
@Nullable
private Size mLatestResolution;
@@ -120,8 +144,9 @@
*
* @param config for this use case instance
*/
+ @SuppressWarnings("WeakerAccess")
@MainThread
- public Preview(@NonNull PreviewConfig config) {
+ Preview(@NonNull PreviewConfig config) {
super(config);
}
@@ -129,13 +154,13 @@
SessionConfig.Builder createPipeline(@NonNull String cameraId, @NonNull PreviewConfig config,
@NonNull Size resolution) {
Threads.checkMainThread();
- Preconditions.checkState(isPreviewSurfaceCallbackSet());
+ Preconditions.checkState(isPreviewSurfaceProviderSet());
SessionConfig.Builder sessionConfigBuilder = SessionConfig.Builder.createFrom(config);
final CaptureProcessor captureProcessor = config.getCaptureProcessor(null);
final CallbackDeferrableSurface callbackDeferrableSurface = new CallbackDeferrableSurface(
- resolution, mPreviewSurfaceCallbackExecutor,
- mPreviewSurfaceCallback);
+ resolution, mPreviewSurfaceProviderExecutor,
+ mPreviewSurfaceProvider);
if (captureProcessor != null) {
CaptureStage captureStage = new CaptureStage.DefaultCaptureStage();
// TODO: To allow user to use an Executor for the processing.
@@ -191,6 +216,7 @@
// TODO(b/143915543): Ensure this never gets called by a camera that is not bound
// to this use case so we don't need to do this check.
if (isCurrentlyBoundCamera(cameraId)) {
+ // Only reset the pipeline when the bound camera is the same.
SessionConfig.Builder sessionConfigBuilder = createPipeline(cameraId, config,
resolution);
@@ -204,7 +230,7 @@
}
/**
- * Gets {@link PreviewSurfaceCallback}
+ * Gets {@link PreviewSurfaceProvider}
*
* <p> Setting the callback will signal to the camera that the use case is ready to receive
* data.
@@ -218,35 +244,37 @@
*/
@UiThread
@Nullable
- public PreviewSurfaceCallback getPreviewSurfaceCallback() {
+ public PreviewSurfaceProvider getPreviewSurfaceProvider() {
Threads.checkMainThread();
- return mPreviewSurfaceCallback;
+ return mPreviewSurfaceProvider;
}
/**
- * Sets a {@link PreviewSurfaceCallback} to provide Surface for Preview.
+ * Sets a {@link PreviewSurfaceProvider} to provide Surface for Preview.
*
- * <p> Setting the callback will signal to the camera that the use case is ready to receive
+ * <p> Setting the provider will signal to the camera that the use case is ready to receive
* data.
*
- * <p> To displaying preview with a {@link TextureView}, consider using
+ * TODO(b/144386349) Remove after minimal version of PreviewView implemented since using with
+ * TextureView is not safe.
+ * <p> To display a preview with a {@link TextureView}, consider using
* {@link PreviewSurfaceProviders#createSurfaceTextureProvider(
*PreviewSurfaceProviders.SurfaceTextureCallback)}
- * to create the callback.
+ * to create the provider.
*
- * @param previewSurfaceCallback PreviewSurfaceCallback that provides a Preview.
- * @param callbackExecutor on which the previewSurfaceCallback will be triggered.
+ * @param executor on which the previewSurfaceProvider will be triggered.
+ * @param previewSurfaceProvider PreviewSurfaceProvider that provides a Preview.
*/
@UiThread
- public void setPreviewSurfaceCallback(@NonNull Executor callbackExecutor,
- @Nullable PreviewSurfaceCallback previewSurfaceCallback) {
+ public void setPreviewSurfaceProvider(@NonNull Executor executor,
+ @Nullable PreviewSurfaceProvider previewSurfaceProvider) {
Threads.checkMainThread();
- if (previewSurfaceCallback == null) {
- mPreviewSurfaceCallback = null;
+ if (previewSurfaceProvider == null) {
+ mPreviewSurfaceProvider = null;
notifyInactive();
} else {
- mPreviewSurfaceCallback = previewSurfaceCallback;
- mPreviewSurfaceCallbackExecutor = callbackExecutor;
+ mPreviewSurfaceProvider = previewSurfaceProvider;
+ mPreviewSurfaceProviderExecutor = executor;
notifyActive();
if (mLatestResolution != null) {
updateConfigAndOutput(getBoundCameraId(), (PreviewConfig) getUseCaseConfig(),
@@ -256,30 +284,30 @@
}
/**
- * Sets a {@link PreviewSurfaceCallback} to provide Surface for Preview.
+ * Sets a {@link PreviewSurfaceProvider} to provide Surface for Preview.
*
- * <p> Setting the callback will signal to the camera that the use case is ready to receive
- * data. The callback will be triggered on main thread.
+ * <p> Setting the provider will signal to the camera that the use case is ready to receive
+ * data. The provider will be triggered on main thread.
*
- * @param previewSurfaceCallback PreviewSurfaceCallback that provides a Preview.
+ * @param previewSurfaceProvider PreviewSurfaceProvider that provides a Preview.
*/
@UiThread
- public void setPreviewSurfaceCallback(@Nullable PreviewSurfaceCallback previewSurfaceCallback) {
- setPreviewSurfaceCallback(CameraXExecutors.mainThreadExecutor(), previewSurfaceCallback);
+ public void setPreviewSurfaceProvider(@Nullable PreviewSurfaceProvider previewSurfaceProvider) {
+ setPreviewSurfaceProvider(CameraXExecutors.mainThreadExecutor(), previewSurfaceProvider);
}
/**
- * Checks if {@link PreviewSurfaceCallback} is set by the user.
+ * Checks if {@link PreviewSurfaceProvider} is set by the user.
*/
@SuppressWarnings("WeakerAccess")
- boolean isPreviewSurfaceCallbackSet() {
- return mPreviewSurfaceCallback != null && mPreviewSurfaceCallbackExecutor != null;
+ boolean isPreviewSurfaceProviderSet() {
+ return mPreviewSurfaceProvider != null && mPreviewSurfaceProviderExecutor != null;
}
private void updateConfigAndOutput(@NonNull String cameraId, @NonNull PreviewConfig config,
@NonNull Size resolution) {
- Preconditions.checkState(isPreviewSurfaceCallbackSet());
+ Preconditions.checkState(isPreviewSurfaceProviderSet());
attachToCamera(cameraId, createPipeline(cameraId, config, resolution).build());
}
@@ -324,7 +352,7 @@
protected UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder(LensFacing lensFacing) {
PreviewConfig defaults = CameraX.getDefaultUseCaseConfig(PreviewConfig.class, lensFacing);
if (defaults != null) {
- return PreviewConfig.Builder.fromConfig(defaults);
+ return Builder.fromConfig(defaults);
}
return null;
@@ -353,10 +381,9 @@
CameraX.getSurfaceManager().getCorrectedAspectRatio(deviceConfig,
imageConfig.getTargetRotation(Surface.ROTATION_0));
if (resultRatio != null) {
- PreviewConfig.Builder configBuilder = PreviewConfig.Builder.fromConfig(
- previewConfig);
+ Builder configBuilder = Builder.fromConfig(previewConfig);
configBuilder.setTargetAspectRatioCustom(resultRatio);
- previewConfig = configBuilder.build();
+ previewConfig = configBuilder.getUseCaseConfig();
}
}
@@ -396,7 +423,7 @@
}
mLatestResolution = resolution;
- if (isPreviewSurfaceCallbackSet()) {
+ if (isPreviewSurfaceProviderSet()) {
updateConfigAndOutput(cameraId, (PreviewConfig) getUseCaseConfig(), resolution);
}
return suggestedResolutionMap;
@@ -404,75 +431,93 @@
/**
- * A callback for the application to provide a {@link Surface} to CameraX.
+ * A interface implemented by the application to provide a {@link Surface} for {@link Preview}.
*
- * <p> This interface is implemented by the application to provide a {@link Surface}, and then
- * called by CameraX when a preview output Surface is needed or is no longer in use by CameraX.
+ * <p> This interface is implemented by the application to provide a {@link Surface}. This
+ * will be called by CameraX when it needs a Surface for Preview. It also signals when the
+ * Surface is no longer in use by CameraX.
*
- * @see Preview#setPreviewSurfaceCallback(PreviewSurfaceCallback)
+ * @see Preview#setPreviewSurfaceProvider(Executor, PreviewSurfaceProvider)
*/
- public interface PreviewSurfaceCallback {
+ public interface PreviewSurfaceProvider {
/**
- * For the application to create an output Surface with the given resolution.
+ * Provides preview output Surface with the given resolution.
*
* <p> This is called when {@link Preview} needs a valid {@link Surface}. e.g. when the
- * {@link Preview} is bound to lifecycle. If the {@link Surface} is backed by a
- * {@link SurfaceTexture}, both the {@link Surface} and the {@link ListenableFuture} need
- * to be recreated each time this is invoked. The application is also responsible to hold
- * a reference to the {@link SurfaceTexture} since the weak reference from
- * {@link Surface} does not prevent it to be garbage collected.
+ * Preview is bound to lifecycle. The Surface should either be backed by a
+ * {@link SurfaceTexture} or a {@link android.view.SurfaceHolder}.
*
- * <p> It's most common to use it with a {@link SurfaceView} or a {@link TextureView}.
- * For {@link TextureView}, {@link PreviewSurfaceProviders} for creating {@link Surface}
- * backed by a {@link SurfaceTexture}. For {@link SurfaceView}, the creation is in the
- * hands of the {@link SurfaceView}. Use {@link CallbackToFutureAdapter} to wait for the
- * creation of the {@link Surface} in {@link android.view.SurfaceHolder.Callback
- * #surfaceChanged(android.view.SurfaceHolder, int, int, int)}. Example:
+ * <p>If the {@link Surface} is backed by a {@link SurfaceTexture}, both the
+ * {@link Surface} and the {@link ListenableFuture} need to be recreated each time this
+ * is invoked. The implementer is also responsible to hold a reference to the
+ * {@link SurfaceTexture} since the weak reference from {@link Surface} does not prevent
+ * it from being garbage collected.
+ *
+ * <p>If the {@link Surface} is backed by a {@link SurfaceView}, the
+ * {@link android.graphics.PixelFormat} should always be the default
+ * {@link android.graphics.PixelFormat#OPAQUE}.
+ *
+ * <p>The application will need to crop and rotate the Surface to fit the UI.
+ *
+ * <p>The resolution that is requested by CameraX will be the sensor resolution, based on
+ * the capabilities of the camera Preview is attached to. The approximate resolution used
+ * for the sensor can be controlled via
+ * {@link Preview.Builder#setTargetResolution(Size)}}. However, the final
+ * resolution that is used might need to be cropped in order to fit the view.
+ *
+ * <p> Undefined behavior may occur if the Surface does not have the requested resolution
+ * or is released before surfaceReleaseFuture completes. So care must be taken when to
+ * using a {@link SurfaceView} or a {@link TextureView} to handle rotation to display
+ * orientation, since they automatically resize and release the Surface.
+ *
+ * Example:
*
* <pre><code>
- * class SurfaceViewHandler implements SurfaceHolder.Callback, PreviewSurfaceCallback {
+ * class MyPreviewSurfaceProvider implements PreviewSurfaceProvider {
*
- * Size mResolution;
- * CallbackToFutureAdapter.Completer<Surface> mCompleter;
+ * SurfaceTexture mSurfaceTexture;
*
* @Override
- * public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- * if (mResolution != null && mCompleter != null && mResolution.getHeight()
- * == height && mResolution.getWidth() == width) {
- * mCompleter.set(holder.getSurface());
- * }
- * }
+ * public ListenableFuture<Surface> provideSurface(@NonNull Size resolution,
+ * @NonNull ListenableFuture<Void> surfaceReleaseFuture) {
+ * // Create the ListenableFuture for the Surface
+ * mSurfaceTexture = new SurfaceTexture(0);
+ * mSurfaceTexture.detachFromGLContext();
+ * ListenableFuture<Surface> surfaceFuture = CallbackToFutureAdapter.getFuture(
+ * completer -> completer.set(new Surface(mSurfaceTexture));
*
- * @Override
- * public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
- * mResolution = resolution;
- * return CallbackToFutureAdapter.getFuture(completer -> {
- * mCompleter = completer
- * });
+ * Futures.addCallback(surfaceReleaseFuture, new FutureCallback<Void>() {
+ * @Override
+ * public void onSuccess(Void result) {
+ * // mSurfaceTexture is no longer used by the camera so it is safe to
+ * // release
+ * mSurfaceTexture.release();
+ * }
+ *
+ * @Override
+ * public void onFailure(Throwable t) {
+ * // Should never fail
+ * }
+ * }, CameraXExecutors.directExecutor());
+ *
+ * return surfaceFuture;
* }
- * }
* </code></pre>
*
- * @param resolution the resolution of the {@link Surface} to create. The value is
- * based on the coordinate system of the image sensor.
- * @return A ListenableFuture that contains the application created Surface.
+ * @param resolution the resolution required by CameraX, which is in image sensor
+ * coordinate system.
+ * @param surfaceReleaseFuture it's safe to release the returned Surface return by the
+ * method, after this {@link ListenableFuture} finishes.
+ * @return A ListenableFuture that contains the implementer created Surface.
+ *
+ * {@see Preview} for rotation details
+ * {@see PreviewConfig.Builder#setTargetResolution(Size)}} for resolution controls
+ * {@see PreviewConfig.Builder#setTargetAspectRatio(int)} for resolution controls
*/
@NonNull
- ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution);
-
- /**
- * Called when the {@link Surface} is safe to be released.
- *
- * <p> This method is called when the {@link Surface} previously returned from
- * {@link #createSurfaceFuture(Size)} is no longer being used by the camera system, and
- * it's safe to be released during or after this is called. The application is
- * responsible to release the {@link Surface} when it's also no longer being used by the
- * app.
- *
- * @param surfaceFuture the {@link Surface} to be released.
- */
- void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture);
+ ListenableFuture<Surface> provideSurface(@NonNull Size resolution,
+ @NonNull ListenableFuture<Void> surfaceReleaseFuture);
}
/**
@@ -492,11 +537,11 @@
private static final PreviewConfig DEFAULT_CONFIG;
static {
- PreviewConfig.Builder builder =
- new PreviewConfig.Builder()
+ Builder builder =
+ new Builder()
.setMaxResolution(DEFAULT_MAX_RESOLUTION)
.setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
- DEFAULT_CONFIG = builder.build();
+ DEFAULT_CONFIG = builder.getUseCaseConfig();
}
@Override
@@ -504,4 +549,427 @@
return DEFAULT_CONFIG;
}
}
+
+ /** Builder for a {@link Preview}. */
+ public static final class Builder
+ implements UseCaseConfig.Builder<Preview, PreviewConfig, Builder>,
+ ImageOutputConfig.Builder<Builder>,
+ CameraDeviceConfig.Builder<Builder>,
+ ThreadConfig.Builder<Builder> {
+
+ private final MutableOptionsBundle mMutableConfig;
+
+ /** Creates a new Builder object. */
+ public Builder() {
+ this(MutableOptionsBundle.create());
+ }
+
+ private Builder(MutableOptionsBundle mutableConfig) {
+ mMutableConfig = mutableConfig;
+
+ Class<?> oldConfigClass =
+ mutableConfig.retrieveOption(TargetConfig.OPTION_TARGET_CLASS, null);
+ if (oldConfigClass != null && !oldConfigClass.equals(Preview.class)) {
+ throw new IllegalArgumentException(
+ "Invalid target class configuration for "
+ + Builder.this
+ + ": "
+ + oldConfigClass);
+ }
+
+ setTargetClass(Preview.class);
+ }
+
+ /**
+ * Generates a Builder from another Config object
+ *
+ * @param configuration An immutable configuration to pre-populate this builder.
+ * @return The new Builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static Builder fromConfig(@NonNull PreviewConfig configuration) {
+ return new Builder(MutableOptionsBundle.from(configuration));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public MutableConfig getMutableConfig() {
+ return mMutableConfig;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public PreviewConfig getUseCaseConfig() {
+ return new PreviewConfig(OptionsBundle.from(mMutableConfig));
+ }
+
+ /**
+ * Builds an immutable {@link Preview} from the current state.
+ *
+ * @return A {@link Preview} populated with the current state.
+ * @throws IllegalArgumentException if attempting to set both target aspect ratio and
+ * target resolution.
+ */
+ @NonNull
+ @Override
+ public Preview build() {
+ // Error at runtime for using both setTargetResolution and setTargetAspectRatio on
+ // the same config.
+ if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
+ && getMutableConfig().retrieveOption(OPTION_TARGET_RESOLUTION, null) != null) {
+ throw new IllegalArgumentException(
+ "Cannot use both setTargetResolution and setTargetAspectRatio on the same "
+ + "config.");
+ }
+ return new Preview(getUseCaseConfig());
+ }
+
+ // Implementations of TargetConfig.Builder default methods
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setTargetClass(@NonNull Class<Preview> targetClass) {
+ getMutableConfig().insertOption(OPTION_TARGET_CLASS, targetClass);
+
+ // If no name is set yet, then generate a unique name
+ if (null == getMutableConfig().retrieveOption(OPTION_TARGET_NAME, null)) {
+ String targetName = targetClass.getCanonicalName() + "-" + UUID.randomUUID();
+ setTargetName(targetName);
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the name of the target object being configured, used only for debug logging.
+ *
+ * <p>The name should be a value that can uniquely identify an instance of the object being
+ * configured.
+ *
+ * <p>If not set, the target name will default to an unique name automatically generated
+ * with the class canonical name and random UUID.
+ *
+ * @param targetName A unique string identifier for the instance of the class being
+ * configured.
+ * @return the current Builder.
+ */
+ @Override
+ @NonNull
+ public Builder setTargetName(@NonNull String targetName) {
+ getMutableConfig().insertOption(OPTION_TARGET_NAME, targetName);
+ return this;
+ }
+
+ // Implementations of CameraDeviceConfig.Builder default methods
+
+ /**
+ * Sets the primary camera to be configured based on the direction the lens is facing.
+ *
+ * <p>If multiple cameras exist with equivalent lens facing direction, the first ("primary")
+ * camera for that direction will be chosen.
+ *
+ * @param lensFacing The direction of the camera's lens.
+ * @return the current Builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setLensFacing(@NonNull LensFacing lensFacing) {
+ getMutableConfig().insertOption(OPTION_LENS_FACING, lensFacing);
+ return this;
+ }
+
+ /**
+ * Sets a {@link CameraIdFilter} that filter out the unavailable camera id.
+ *
+ * <p>The camera id filter will be used to filter those cameras with lens facing
+ * specified in the config.
+ *
+ * @param cameraIdFilter The {@link CameraIdFilter}.
+ * @return the current Builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setCameraIdFilter(@NonNull CameraIdFilter cameraIdFilter) {
+ getMutableConfig().insertOption(OPTION_CAMERA_ID_FILTER, cameraIdFilter);
+ return this;
+ }
+
+ // Implementations of ImageOutputConfig.Builder default methods
+
+ /**
+ * Sets the aspect ratio of the intended target for images from this configuration.
+ *
+ * <p>This is the ratio of the target's width to the image's height, where the numerator of
+ * the provided {@link Rational} corresponds to the width, and the denominator corresponds
+ * to the height.
+ *
+ * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
+ * ratio which may differ from the request, possibly due to device constraints.
+ * Application code should check the resulting output's resolution.
+ *
+ * <p>This method can be used to request an aspect ratio that is not from the standard set
+ * of aspect ratios defined in the {@link AspectRatio}.
+ *
+ * <p>This method will remove any value set by setTargetAspectRatio().
+ *
+ * <p>For Preview, the value will be used to calculate the suggested resolution size in
+ * {@link Preview.PreviewSurfaceCallback#createSurfaceFuture(Size)}.
+ *
+ * @param aspectRatio A {@link Rational} representing the ratio of the target's width and
+ * height.
+ * @return The current Builder.
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ public Builder setTargetAspectRatioCustom(@NonNull Rational aspectRatio) {
+ getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM, aspectRatio);
+ getMutableConfig().removeOption(OPTION_TARGET_ASPECT_RATIO);
+ return this;
+ }
+
+ /**
+ * Sets the aspect ratio of the intended target for images from this configuration.
+ *
+ * <p>It is not allowed to set both target aspect ratio and target resolution on the same
+ * use case. Attempting so will throw an IllegalArgumentException when building the
+ * Config.
+ *
+ * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
+ * ratio which may differ from the request, possibly due to device constraints.
+ * Application code should check the resulting output's resolution.
+ *
+ * <p>For Preview, the value will be used to calculate the suggested resolution size in
+ * {@link Preview.PreviewSurfaceProvider#provideSurface(Size, ListenableFuture)}.
+ *
+ * <p>If not set, resolutions with aspect ratio 4:3 will be considered in higher
+ * priority.
+ *
+ * @param aspectRatio A {@link AspectRatio} representing the ratio of the
+ * target's width and height.
+ * @return The current Builder.
+ */
+ @NonNull
+ @Override
+ public Builder setTargetAspectRatio(@AspectRatio int aspectRatio) {
+ getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO, aspectRatio);
+ return this;
+ }
+
+ /**
+ * Sets the rotation of the intended target for images from this configuration.
+ *
+ * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link
+ * Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
+ * Rotation values are relative to the "natural" rotation, {@link Surface#ROTATION_0}.
+ *
+ * <p>If not set, the target rotation will default to the value of
+ * {@link Display#getRotation()} of the default display at the time the use case is created.
+ *
+ * @param rotation The rotation of the intended target.
+ * @return The current Builder.
+ * @hide Preview always set the rotation to device's nature orientation.
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ @Override
+ public Builder setTargetRotation(@ImageOutputConfig.RotationValue int rotation) {
+ getMutableConfig().insertOption(OPTION_TARGET_ROTATION, rotation);
+ return this;
+ }
+
+ /**
+ * Sets the resolution of the intended target from this configuration.
+ *
+ * <p>The target resolution attempts to establish a minimum bound for the preview
+ * resolution. The actual preview resolution will be the closest available resolution in
+ * size that is not smaller than the target resolution, as determined by the Camera
+ * implementation. However, if no resolution exists that is equal to or larger than the
+ * target resolution, the nearest available resolution smaller than the target resolution
+ * will be chosen. Resolutions with the same aspect ratio of the provided {@link Size} will
+ * be considered in higher priority before resolutions of different aspect ratios.
+ *
+ * <p>It is not allowed to set both target aspect ratio and target resolution on the same
+ * use case. Attempting so will throw an IllegalArgumentException when building the
+ * Config.
+ *
+ * <p>The resolution {@link Size} should be expressed at the use cases's target rotation.
+ * For example, a device with portrait natural orientation in natural target rotation
+ * requesting a portrait image may specify 480x640, and the same device, rotated 90 degrees
+ * and targeting landscape orientation may specify 640x480.
+ *
+ * <p>The maximum available resolution that could be selected for a {@link Preview} is
+ * limited to be under 1080p. The limitation of 1080p for {@link Preview} has considered
+ * both performance and quality factors that users can obtain reasonable quality and smooth
+ * output stream under 1080p.
+ *
+ * <p>If not set, the default selected resolution will be the best size match to the
+ * device's screen resolution, or to 1080p (1920x1080), whichever is smaller.
+ *
+ * @param resolution The target resolution to choose from supported output sizes list.
+ * @return The current Builder.
+ */
+ @NonNull
+ @Override
+ public Builder setTargetResolution(@NonNull Size resolution) {
+ getMutableConfig()
+ .insertOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION, resolution);
+ if (resolution != null) {
+ getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM,
+ new Rational(resolution.getWidth(), resolution.getHeight()));
+ }
+ return this;
+ }
+
+ /**
+ * Sets the default resolution of the intended target from this configuration.
+ *
+ * @param resolution The default resolution to choose from supported output sizes list.
+ * @return The current Builder.
+ * @hide
+ */
+ @NonNull
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ public Builder setDefaultResolution(@NonNull Size resolution) {
+ getMutableConfig().insertOption(OPTION_DEFAULT_RESOLUTION, resolution);
+ return this;
+ }
+
+ /** @hide */
+ @NonNull
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ public Builder setMaxResolution(@NonNull Size resolution) {
+ getMutableConfig().insertOption(OPTION_MAX_RESOLUTION, resolution);
+ return this;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setSupportedResolutions(@NonNull List<Pair<Integer, Size[]>> resolutions) {
+ getMutableConfig().insertOption(OPTION_SUPPORTED_RESOLUTIONS, resolutions);
+ return this;
+ }
+
+ // Implementations of ThreadConfig.Builder default methods
+
+ /**
+ * Sets the default executor that will be used for background tasks.
+ *
+ * <p>If not set, the background executor will default to an automatically generated
+ * {@link Executor}.
+ *
+ * @param executor The executor which will be used for background tasks.
+ * @return the current Builder.
+ * @hide Background executor not used in {@link Preview}.
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setBackgroundExecutor(@NonNull Executor executor) {
+ getMutableConfig().insertOption(OPTION_BACKGROUND_EXECUTOR, executor);
+ return this;
+ }
+
+ // Implementations of UseCaseConfig.Builder default methods
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setDefaultSessionConfig(@NonNull SessionConfig sessionConfig) {
+ getMutableConfig().insertOption(OPTION_DEFAULT_SESSION_CONFIG, sessionConfig);
+ return this;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setDefaultCaptureConfig(@NonNull CaptureConfig captureConfig) {
+ getMutableConfig().insertOption(OPTION_DEFAULT_CAPTURE_CONFIG, captureConfig);
+ return this;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setSessionOptionUnpacker(
+ @NonNull SessionConfig.OptionUnpacker optionUnpacker) {
+ getMutableConfig().insertOption(OPTION_SESSION_CONFIG_UNPACKER, optionUnpacker);
+ return this;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setCaptureOptionUnpacker(
+ @NonNull CaptureConfig.OptionUnpacker optionUnpacker) {
+ getMutableConfig().insertOption(OPTION_CAPTURE_CONFIG_UNPACKER, optionUnpacker);
+ return this;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setSurfaceOccupancyPriority(int priority) {
+ getMutableConfig().insertOption(OPTION_SURFACE_OCCUPANCY_PRIORITY, priority);
+ return this;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Override
+ @NonNull
+ public Builder setUseCaseEventCallback(
+ @NonNull UseCase.EventCallback useCaseEventCallback) {
+ getMutableConfig().insertOption(OPTION_USE_CASE_EVENT_CALLBACK, useCaseEventCallback);
+ return this;
+ }
+
+ /** @hide */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public Builder setImageInfoProcessor(@NonNull ImageInfoProcessor processor) {
+ getMutableConfig().insertOption(IMAGE_INFO_PROCESSOR, processor);
+ return this;
+ }
+
+ /**
+ * Sets the {@link CaptureProcessor}.
+ *
+ * @param captureProcessor The requested capture processor for extension.
+ * @return The current Builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public Builder setCaptureProcessor(@NonNull CaptureProcessor captureProcessor) {
+ getMutableConfig().insertOption(OPTION_PREVIEW_CAPTURE_PROCESSOR, captureProcessor);
+ return this;
+ }
+ }
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
index 6c303fe..9f146da 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
@@ -19,7 +19,6 @@
import android.util.Pair;
import android.util.Rational;
import android.util.Size;
-import android.view.Display;
import android.view.Surface;
import androidx.annotation.NonNull;
@@ -29,10 +28,14 @@
import java.util.List;
import java.util.Set;
-import java.util.UUID;
import java.util.concurrent.Executor;
-/** Configuration for a {@link Preview} use case. */
+/**
+ * Configuration for a {@link Preview} use case.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY_GROUP)
public final class PreviewConfig
implements UseCaseConfig<Preview>,
ImageOutputConfig,
@@ -258,17 +261,9 @@
return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
}
- /**
- * Retrieves the aspect ratio of the target intending to use images from this configuration.
- *
- * @param valueIfMissing The value to return if this configuration option has not been set.
- * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
- * configuration.
- */
- @Nullable
@Override
- public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
- return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+ public boolean hasTargetAspectRatio() {
+ return containsOption(OPTION_TARGET_ASPECT_RATIO);
}
/**
@@ -578,417 +573,4 @@
// End of the default implementation of Config
// *********************************************************************************************
-
- /** Builder for a {@link PreviewConfig}. */
- public static final class Builder
- implements UseCaseConfig.Builder<Preview, PreviewConfig, Builder>,
- ImageOutputConfig.Builder<Builder>,
- CameraDeviceConfig.Builder<Builder>,
- ThreadConfig.Builder<Builder> {
-
- private final MutableOptionsBundle mMutableConfig;
-
- /** Creates a new Builder object. */
- public Builder() {
- this(MutableOptionsBundle.create());
- }
-
- private Builder(MutableOptionsBundle mutableConfig) {
- mMutableConfig = mutableConfig;
-
- Class<?> oldConfigClass =
- mutableConfig.retrieveOption(TargetConfig.OPTION_TARGET_CLASS, null);
- if (oldConfigClass != null && !oldConfigClass.equals(Preview.class)) {
- throw new IllegalArgumentException(
- "Invalid target class configuration for "
- + Builder.this
- + ": "
- + oldConfigClass);
- }
-
- setTargetClass(Preview.class);
- }
-
- /**
- * Generates a Builder from another Config object
- *
- * @param configuration An immutable configuration to pre-populate this builder.
- * @return The new Builder.
- */
- @NonNull
- public static Builder fromConfig(@NonNull PreviewConfig configuration) {
- return new Builder(MutableOptionsBundle.from(configuration));
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public MutableConfig getMutableConfig() {
- return mMutableConfig;
- }
-
- /**
- * Builds an immutable {@link PreviewConfig} from the current state.
- *
- * @return A {@link PreviewConfig} populated with the current state.
- * @throws IllegalArgumentException if attempting to set both target aspect ratio and
- * target resolution.
- */
- @NonNull
- @Override
- public PreviewConfig build() {
- // Error at runtime for using both setTargetResolution and setTargetAspectRatio on
- // the same config.
- if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
- && getMutableConfig().retrieveOption(OPTION_TARGET_RESOLUTION, null) != null) {
- throw new IllegalArgumentException(
- "Cannot use both setTargetResolution and setTargetAspectRatio on the same "
- + "config.");
- }
- return new PreviewConfig(OptionsBundle.from(mMutableConfig));
- }
-
- // Implementations of TargetConfig.Builder default methods
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setTargetClass(@NonNull Class<Preview> targetClass) {
- getMutableConfig().insertOption(OPTION_TARGET_CLASS, targetClass);
-
- // If no name is set yet, then generate a unique name
- if (null == getMutableConfig().retrieveOption(OPTION_TARGET_NAME, null)) {
- String targetName = targetClass.getCanonicalName() + "-" + UUID.randomUUID();
- setTargetName(targetName);
- }
-
- return this;
- }
-
- /**
- * Sets the name of the target object being configured.
- *
- * <p>The name should be a value that can uniquely identify an instance of the object being
- * configured.
- *
- * <p>If not set, the target name will default to an unique name automatically generated
- * with the class canonical name and random UUID.
- *
- * @param targetName A unique string identifier for the instance of the class being
- * configured.
- * @return the current Builder.
- */
- @Override
- @NonNull
- public Builder setTargetName(@NonNull String targetName) {
- getMutableConfig().insertOption(OPTION_TARGET_NAME, targetName);
- return this;
- }
-
- // Implementations of CameraDeviceConfig.Builder default methods
-
- /**
- * Sets the primary camera to be configured based on the direction the lens is facing.
- *
- * <p>If multiple cameras exist with equivalent lens facing direction, the first ("primary")
- * camera for that direction will be chosen.
- *
- * @param lensFacing The direction of the camera's lens.
- * @return the current Builder.
- * @hide
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setLensFacing(@NonNull LensFacing lensFacing) {
- getMutableConfig().insertOption(OPTION_LENS_FACING, lensFacing);
- return this;
- }
-
- /**
- * Sets a {@link CameraIdFilter} that filter out the unavailable camera id.
- *
- * <p>The camera id filter will be used to filter those cameras with lens facing
- * specified in the config.
- *
- * @param cameraIdFilter The {@link CameraIdFilter}.
- * @return the current Builder.
- * @hide
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setCameraIdFilter(@NonNull CameraIdFilter cameraIdFilter) {
- getMutableConfig().insertOption(OPTION_CAMERA_ID_FILTER, cameraIdFilter);
- return this;
- }
-
- // Implementations of ImageOutputConfig.Builder default methods
-
- /**
- * Sets the aspect ratio of the intended target for images from this configuration.
- *
- * <p>This is the ratio of the target's width to the image's height, where the numerator of
- * the provided {@link Rational} corresponds to the width, and the denominator corresponds
- * to the height.
- *
- * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
- * ratio which may differ from the request, possibly due to device constraints.
- * Application code should check the resulting output's resolution.
- *
- * <p>This method can be used to request an aspect ratio that is not from the standard set
- * of aspect ratios defined in the {@link AspectRatio}.
- *
- * <p>This method will remove any value set by setTargetAspectRatio().
- *
- * <p>For Preview, the value will be used to calculate the suggested resolution size in
- * {@link Preview.PreviewSurfaceCallback#createSurfaceFuture(Size)}.
- *
- * @param aspectRatio A {@link Rational} representing the ratio of the target's width and
- * height.
- * @return The current Builder.
- * @hide
- */
- @NonNull
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- public Builder setTargetAspectRatioCustom(@NonNull Rational aspectRatio) {
- getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM, aspectRatio);
- getMutableConfig().removeOption(OPTION_TARGET_ASPECT_RATIO);
- return this;
- }
-
- /**
- * Sets the aspect ratio of the intended target for images from this configuration.
- *
- * <p>It is not allowed to set both target aspect ratio and target resolution on the same
- * use case. Attempting so will throw an IllegalArgumentException when building the
- * Config.
- *
- * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
- * ratio which may differ from the request, possibly due to device constraints.
- * Application code should check the resulting output's resolution.
- *
- * <p>For Preview, the value will be used to calculate the suggested resolution size in
- * {@link Preview.PreviewSurfaceCallback#createSurfaceFuture(Size)}.
- *
- * <p>If not set, resolutions with aspect ratio 4:3 will be considered in higher
- * priority.
- *
- * @param aspectRatio A {@link AspectRatio} representing the ratio of the
- * target's width and height.
- * @return The current Builder.
- */
- @NonNull
- @Override
- public Builder setTargetAspectRatio(@AspectRatio int aspectRatio) {
- getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO, aspectRatio);
- return this;
- }
-
- /**
- * Sets the rotation of the intended target for images from this configuration.
- *
- * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link
- * Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
- * Rotation values are relative to the "natural" rotation, {@link Surface#ROTATION_0}.
- *
- * <p>If not set, the target rotation will default to the value of
- * {@link Display#getRotation()} of the default display at the time the use case is created.
- *
- * @param rotation The rotation of the intended target.
- * @return The current Builder.
- * @hide Preview always set the rotation to device's nature orientation.
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- @Override
- public Builder setTargetRotation(@RotationValue int rotation) {
- getMutableConfig().insertOption(OPTION_TARGET_ROTATION, rotation);
- return this;
- }
-
- /**
- * Sets the resolution of the intended target from this configuration.
- *
- * <p>The target resolution attempts to establish a minimum bound for the preview
- * resolution. The actual preview resolution will be the closest available resolution in
- * size that is not smaller than the target resolution, as determined by the Camera
- * implementation. However, if no resolution exists that is equal to or larger than the
- * target resolution, the nearest available resolution smaller than the target resolution
- * will be chosen. Resolutions with the same aspect ratio of the provided {@link Size} will
- * be considered in higher priority before resolutions of different aspect ratios.
- *
- * <p>It is not allowed to set both target aspect ratio and target resolution on the same
- * use case. Attempting so will throw an IllegalArgumentException when building the
- * Config.
- *
- * <p>The resolution {@link Size} should be expressed at the use cases's target rotation.
- * For example, a device with portrait natural orientation in natural target rotation
- * requesting a portrait image may specify 480x640, and the same device, rotated 90 degrees
- * and targeting landscape orientation may specify 640x480.
- *
- * <p>The maximum available resolution that could be selected for a {@link Preview} is
- * limited to be under 1080p. The limitation of 1080p for {@link Preview} has considered
- * both performance and quality factors that users can obtain reasonable quality and smooth
- * output stream under 1080p.
- *
- * <p>If not set, the default selected resolution will be the best size match to the
- * device's screen resolution, or to 1080p (1920x1080), whichever is smaller.
- *
- * @param resolution The target resolution to choose from supported output sizes list.
- * @return The current Builder.
- */
- @NonNull
- @Override
- public Builder setTargetResolution(@NonNull Size resolution) {
- getMutableConfig()
- .insertOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION, resolution);
- if (resolution != null) {
- getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM,
- new Rational(resolution.getWidth(), resolution.getHeight()));
- }
- return this;
- }
-
- /**
- * Sets the default resolution of the intended target from this configuration.
- *
- * @param resolution The default resolution to choose from supported output sizes list.
- * @return The current Builder.
- * @hide
- */
- @NonNull
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- public Builder setDefaultResolution(@NonNull Size resolution) {
- getMutableConfig().insertOption(OPTION_DEFAULT_RESOLUTION, resolution);
- return this;
- }
-
- /** @hide */
- @NonNull
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- public Builder setMaxResolution(@NonNull Size resolution) {
- getMutableConfig().insertOption(OPTION_MAX_RESOLUTION, resolution);
- return this;
- }
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setSupportedResolutions(@NonNull List<Pair<Integer, Size[]>> resolutions) {
- getMutableConfig().insertOption(OPTION_SUPPORTED_RESOLUTIONS, resolutions);
- return this;
- }
-
- // Implementations of ThreadConfig.Builder default methods
-
- /**
- * Sets the default executor that will be used for background tasks.
- *
- * <p>If not set, the background executor will default to an automatically generated
- * {@link Executor}.
- *
- * @param executor The executor which will be used for background tasks.
- * @return the current Builder.
- * @hide Background executor not used in {@link Preview}.
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setBackgroundExecutor(@NonNull Executor executor) {
- getMutableConfig().insertOption(OPTION_BACKGROUND_EXECUTOR, executor);
- return this;
- }
-
- // Implementations of UseCaseConfig.Builder default methods
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setDefaultSessionConfig(@NonNull SessionConfig sessionConfig) {
- getMutableConfig().insertOption(OPTION_DEFAULT_SESSION_CONFIG, sessionConfig);
- return this;
- }
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setDefaultCaptureConfig(@NonNull CaptureConfig captureConfig) {
- getMutableConfig().insertOption(OPTION_DEFAULT_CAPTURE_CONFIG, captureConfig);
- return this;
- }
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setSessionOptionUnpacker(
- @NonNull SessionConfig.OptionUnpacker optionUnpacker) {
- getMutableConfig().insertOption(OPTION_SESSION_CONFIG_UNPACKER, optionUnpacker);
- return this;
- }
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setCaptureOptionUnpacker(
- @NonNull CaptureConfig.OptionUnpacker optionUnpacker) {
- getMutableConfig().insertOption(OPTION_CAPTURE_CONFIG_UNPACKER, optionUnpacker);
- return this;
- }
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setSurfaceOccupancyPriority(int priority) {
- getMutableConfig().insertOption(OPTION_SURFACE_OCCUPANCY_PRIORITY, priority);
- return this;
- }
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @Override
- @NonNull
- public Builder setUseCaseEventCallback(
- @NonNull UseCase.EventCallback useCaseEventCallback) {
- getMutableConfig().insertOption(OPTION_USE_CASE_EVENT_CALLBACK, useCaseEventCallback);
- return this;
- }
-
- /** @hide */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public Builder setImageInfoProcessor(@NonNull ImageInfoProcessor processor) {
- getMutableConfig().insertOption(IMAGE_INFO_PROCESSOR, processor);
- return this;
- }
-
- /**
- * Sets the {@link CaptureProcessor}.
- *
- * @param captureProcessor The requested capture processor for extension.
- * @return The current Builder.
- * @hide
- */
- @RestrictTo(Scope.LIBRARY_GROUP)
- @NonNull
- public Builder setCaptureProcessor(@NonNull CaptureProcessor captureProcessor) {
- getMutableConfig().insertOption(OPTION_PREVIEW_CAPTURE_PROCESSOR, captureProcessor);
- return this;
- }
- }
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java b/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java
index edd9033..371399e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java
@@ -17,22 +17,16 @@
package androidx.camera.core;
import android.graphics.SurfaceTexture;
-import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import androidx.annotation.NonNull;
+import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
/**
- * This class creates implementations of PreviewSurfaceCallback that provide Surfaces that have been
+ * This class creates implementations of PreviewSurfaceProvider that provide Surfaces that have been
* pre-configured for specific work flows.
*/
public final class PreviewSurfaceProviders {
@@ -43,23 +37,21 @@
}
/**
- * Creates a {@link Preview.PreviewSurfaceCallback} that is backed by a {@link SurfaceTexture}.
+ * Creates a {@link Preview.PreviewSurfaceProvider} that is backed by a {@link SurfaceTexture}.
*
- * <p>This is a convenience method for creating a {@link Preview.PreviewSurfaceCallback}
+ * <p>This is a convenience method for creating a {@link Preview.PreviewSurfaceProvider}
* whose {@link Surface} is backed by a {@link SurfaceTexture}. The returned
- * {@link Preview.PreviewSurfaceCallback} is responsible for creating the {@link SurfaceTexture}
- * and propagating {@link Preview.PreviewSurfaceCallback#onSafeToRelease(ListenableFuture)}
- * back to the implementer. The {@link SurfaceTexture} is usually used with a
- * {@link TextureView}.
+ * {@link Preview.PreviewSurfaceProvider} is responsible for creating the
+ * {@link SurfaceTexture}. The {@link SurfaceTexture} may not be safe to use with
+ * {@link TextureView}
* Example:
*
* <pre><code>
- * preview.setPreviewSurfaceCallback(createPreviewSurfaceCallback(
+ * preview.setPreviewSurfaceProvider(createPreviewSurfaceProvider(
* new PreviewSurfaceProviders.SurfaceTextureCallback() {
* @Override
* public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture) {
- * // Maybe remove and re-add the TextureView to its parent.
- * textureView.setSurfaceTexture(surfaceTexture);
+ * // Use the SurfaceTexture
* }
*
* @Override
@@ -69,49 +61,26 @@
* }));
* </code></pre>
*
- * <p> Note that the TextureView needs to be removed and re-added from the parent view for the
- * SurfaceTexture to be attached, because TextureView's existing SurfaceTexture is only
- * correctly detached once the parent TextureView is removed from the view hierarchy.
- *
* @param surfaceTextureCallback callback called when the SurfaceTexture is ready to be
* set/released.
- * @return a {@link Preview.PreviewSurfaceCallback} to be used with
- * {@link Preview#setPreviewSurfaceCallback(Preview.PreviewSurfaceCallback)}.
+ * @return a {@link Preview.PreviewSurfaceProvider} to be used with
+ * {@link Preview#setPreviewSurfaceProvider(Preview.PreviewSurfaceProvider)}.
*/
@NonNull
- public static Preview.PreviewSurfaceCallback createSurfaceTextureProvider(
+ public static Preview.PreviewSurfaceProvider createSurfaceTextureProvider(
@NonNull SurfaceTextureCallback surfaceTextureCallback) {
- return new Preview.PreviewSurfaceCallback() {
-
- Map<Surface, SurfaceTexture> mSurfaceTextureMap = new HashMap<>();
-
- @NonNull
- @Override
- public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
- SurfaceTexture surfaceTexture = new SurfaceTexture(0);
- surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
- resolution.getHeight());
- surfaceTexture.detachFromGLContext();
- surfaceTextureCallback.onSurfaceTextureReady(surfaceTexture, resolution);
- Surface surface = new Surface(surfaceTexture);
- mSurfaceTextureMap.put(surface, surfaceTexture);
- return Futures.immediateFuture(surface);
- }
-
- @Override
- public void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture) {
- try {
- Surface surface = surfaceFuture.get();
- SurfaceTexture surfaceTexture = mSurfaceTextureMap.get(surface);
- if (surfaceTexture != null) {
- surfaceTextureCallback.onSafeToRelease(surfaceTexture);
- mSurfaceTextureMap.remove(surface);
- }
- surface.release();
- } catch (ExecutionException | InterruptedException e) {
- Log.w(TAG, "Failed to release the Surface.", e);
- }
- }
+ return (resolution, safeToCancelFuture) -> {
+ SurfaceTexture surfaceTexture = new SurfaceTexture(0);
+ surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
+ resolution.getHeight());
+ surfaceTexture.detachFromGLContext();
+ surfaceTextureCallback.onSurfaceTextureReady(surfaceTexture, resolution);
+ Surface surface = new Surface(surfaceTexture);
+ safeToCancelFuture.addListener(() -> {
+ surface.release();
+ surfaceTextureCallback.onSafeToRelease(surfaceTexture);
+ }, CameraXExecutors.directExecutor());
+ return Futures.immediateFuture(surface);
};
}
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 8bdb381..6df4dcb 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
@@ -93,7 +93,6 @@
* Creates a named instance of the use case.
*
* @param useCaseConfig the configuration object used for this use case
- *
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -162,7 +161,7 @@
*
* @param userConfig The user-supplied configuration.
* @param defaultConfigBuilder A builder containing use-case default values, or {@code null}
- * if no default values exist.
+ * if no default values exist.
* @return The configuration that will be used by this use case.
* @hide
*/
@@ -186,10 +185,9 @@
objectOpt, userConfig.retrieveOption(objectOpt));
}
- @SuppressWarnings(
- "unchecked") // Since builder is a UseCaseConfig.Builder, it should produce a
- // UseCaseConfig
- UseCaseConfig<?> defaultConfig = defaultConfigBuilder.build();
+ // Since builder is a UseCaseConfig.Builder, it should produce a UseCaseConfig
+ @SuppressWarnings("unchecked")
+ UseCaseConfig<?> defaultConfig = defaultConfigBuilder.getUseCaseConfig();
return defaultConfig;
}
@@ -370,6 +368,7 @@
/**
* Returns the camera ID for the currently bound camera, or throws an exception if no camera is
* bound.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -382,6 +381,7 @@
/**
* Checks whether the provided camera ID is the currently bound camera ID.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -392,8 +392,7 @@
boundCameraId = getCameraIdUnchecked(deviceConfig);
}
- // Bound camera changed. Don't attempt reset.
- return !Objects.equals(cameraId, boundCameraId);
+ return Objects.equals(cameraId, boundCameraId);
}
/**
@@ -437,6 +436,7 @@
/**
* Returns the currently bound {@link CameraDeviceConfig} or {@code null} if none is bound.
* TODO(b/142840814): Only rely on attached Camera rather than config.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -490,7 +490,6 @@
* bound.
* @return The map with the resolutions that finally used to create the SessionConfig to
* attach to the camera device.
- *
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@@ -529,6 +528,7 @@
/**
* Called when use case is online in camera. This method is called on main thread.
+ *
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java
index 24a0b98..39c7427 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java
@@ -234,10 +234,11 @@
int getSurfaceOccupancyPriority();
/**
- * Builder for a {@link UseCaseConfig}.
+ * Builder for a {@link UseCase}.
*
- * @param <T> The type of the object being configured.
- * @param <C> The top level configuration which will be generated by {@link #build()}.
+ * @param <T> The type of the object which will be built by {@link #build()}.
+ * @param <C> The top level configuration which will be generated by
+ * {@link #getUseCaseConfig()}.
* @param <B> The top level builder type for which this builder is composed with.
* @hide
*/
@@ -313,12 +314,22 @@
B setSurfaceOccupancyPriority(int priority);
/**
- * Builds the configuration for the target use case.
+ * Retrieves the configuration used by this builder.
+ *
+ * @return the configuration used by this builder.
+ * @hide
+ */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ C getUseCaseConfig();
+
+ /**
+ * Builds the target use case using the configuration.
*
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
- C build();
+ T build();
}
}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
index 79e6c70..ebfcb54 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
@@ -441,7 +441,7 @@
int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != rotation) {
mUseCaseConfigBuilder.setTargetRotation(rotation);
- updateUseCaseConfig(mUseCaseConfigBuilder.build());
+ updateUseCaseConfig(mUseCaseConfigBuilder.getUseCaseConfig());
// TODO(b/122846516): Update session configuration and possibly reconfigure session.
}
@@ -481,6 +481,7 @@
// TODO(b/143915543): Ensure this never gets called by a camera that is not bound
// to this use case so we don't need to do this check.
if (isCurrentlyBoundCamera(cameraId)) {
+ // Only reset the pipeline when the bound camera is the same.
setupEncoder(cameraId, resolution);
}
}
@@ -934,7 +935,7 @@
.setMaxResolution(DEFAULT_MAX_RESOLUTION)
.setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
- DEFAULT_CONFIG = builder.build();
+ DEFAULT_CONFIG = builder.getUseCaseConfig();
}
@Override
@@ -952,8 +953,10 @@
private final class VideoSavedListenerWrapper implements OnVideoSavedCallback {
- @NonNull Executor mExecutor;
- @NonNull OnVideoSavedCallback mOnVideoSavedCallback;
+ @NonNull
+ Executor mExecutor;
+ @NonNull
+ OnVideoSavedCallback mOnVideoSavedCallback;
VideoSavedListenerWrapper(@NonNull Executor executor,
@NonNull OnVideoSavedCallback onVideoSavedCallback) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
index b4fc308..1164d75 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
@@ -462,17 +462,9 @@
return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
}
- /**
- * Retrieves the aspect ratio of the target intending to use images from this configuration.
- *
- * @param valueIfMissing The value to return if this configuration option has not been set.
- * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
- * configuration.
- */
- @Nullable
@Override
- public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
- return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+ public boolean hasTargetAspectRatio() {
+ return containsOption(OPTION_TARGET_ASPECT_RATIO);
}
/**
@@ -781,6 +773,12 @@
return mMutableConfig;
}
+ @NonNull
+ @Override
+ public VideoCaptureConfig getUseCaseConfig() {
+ return new VideoCaptureConfig(OptionsBundle.from(mMutableConfig));
+ }
+
/**
* Builds an immutable {@link VideoCaptureConfig} from the current state.
*
@@ -788,7 +786,7 @@
*/
@Override
@NonNull
- public VideoCaptureConfig build() {
+ public VideoCapture build() {
// Error at runtime for using both setTargetResolution and setTargetAspectRatio on
// the same config.
if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
@@ -797,7 +795,7 @@
"Cannot use both setTargetResolution and setTargetAspectRatio on the same "
+ "config.");
}
- return new VideoCaptureConfig(OptionsBundle.from(mMutableConfig));
+ return new VideoCapture(getUseCaseConfig());
}
/**
@@ -925,7 +923,7 @@
}
/**
- * Sets the name of the target object being configured.
+ * Sets the name of the target object being configured, used only for debug logging.
*
* <p>The name should be a value that can uniquely identify an instance of the object being
* configured.
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java b/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java
index 0faee6a..2fdadc8 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java
@@ -62,7 +62,7 @@
new ConfigProvider<FakeUseCaseConfig>() {
@Override
public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
- return new FakeUseCaseConfig.Builder().build();
+ return new FakeUseCaseConfig.Builder().getUseCaseConfig();
}
});
FakeCameraFactory cameraFactory = new FakeCameraFactory();
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java
index 98a7228..93a370b 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java
@@ -57,7 +57,7 @@
@Override
public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
- return new FakeUseCaseConfig.Builder().build();
+ return new FakeUseCaseConfig.Builder().getUseCaseConfig();
}
}
}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
index 7af61a1..8e63da3 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
@@ -214,11 +214,11 @@
private void setUpImageAnalysisWithStrategy(
@ImageAnalysis.BackpressureStrategy int backpressureStrategy) {
- mImageAnalysis = new ImageAnalysis(new ImageAnalysisConfig.Builder()
+ mImageAnalysis = new ImageAnalysisConfig.Builder()
.setBackgroundExecutor(mBackgroundExecutor)
.setImageQueueDepth(QUEUE_DEPTH)
.setBackpressureStrategy(backpressureStrategy)
- .build());
+ .build();
mImageAnalysis.setAnalyzer(CameraXExecutors.newHandlerExecutor(mCallbackHandler),
(image, rotationDegrees) -> {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java b/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
index a37e865..f57ee37f 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
@@ -39,7 +39,7 @@
@NonNull SessionConfig.Builder builder) {
// no op.
}
- }).build();
+ }).getUseCaseConfig();
private static final CameraInfo DEFAULT_CAMERA_INFO = new CameraInfoInternal() {
MutableLiveData<Boolean> mFlashAvailability = new MutableLiveData<>(Boolean.TRUE);
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
index f62c775..30a4d3a 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
@@ -141,7 +141,7 @@
mInstrumentation.runOnMainSync(
() -> {
// To set the update listener and Preview will change to active state.
- preview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+ preview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java
index 4160d07..7d8d041 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java
@@ -119,7 +119,7 @@
imageCaptureAdapter).setCaptureProcessor(
mock(CaptureProcessor.class));
- ImageCapture useCase = new ImageCapture(configBuilder.build());
+ ImageCapture useCase = configBuilder.build();
LensFacing lensFacing = CameraX.getDefaultLensFacing();
CameraSelector cameraSelector = new CameraSelector.Builder()
@@ -177,7 +177,7 @@
new Camera2Config.Extender(configBuilder).setCameraEventCallback(
new CameraEventCallbacks(imageCaptureAdapter));
- ImageCapture useCase = new ImageCapture(configBuilder.build());
+ ImageCapture useCase = configBuilder.build();
LensFacing lensFacing = CameraX.getDefaultLensFacing();
CameraSelector cameraSelector = new CameraSelector.Builder()
@@ -242,14 +242,14 @@
mockImageCaptureExtenderImpl);
// Checks the config does not include supported resolutions before applying effect mode.
- assertThat(configBuilder.build().getSupportedResolutions(null)).isNull();
+ assertThat(configBuilder.getUseCaseConfig().getSupportedResolutions(null)).isNull();
// Checks the config includes supported resolutions after applying effect mode.
CameraSelector selector =
new CameraSelector.Builder().requireLensFacing(lensFacing).build();
fakeExtender.enableExtension(selector);
List<Pair<Integer, Size[]>> resultFormatResolutionsPairList =
- configBuilder.build().getSupportedResolutions(null);
+ configBuilder.getUseCaseConfig().getSupportedResolutions(null);
assertThat(resultFormatResolutionsPairList).isNotNull();
// Checks the result and target pair lists are the same
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java
index 32073df..7da28b3 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java
@@ -50,7 +50,6 @@
import androidx.camera.core.CameraX;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.core.PreviewSurfaceProviders;
import androidx.camera.extensions.ExtensionsManager.EffectMode;
import androidx.camera.extensions.impl.CaptureStageImpl;
@@ -139,7 +138,7 @@
when(mockPreviewExtenderImpl.isExtensionAvailable(any(String.class),
any(CameraCharacteristics.class))).thenReturn(true);
- PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+ Preview.Builder configBuilder = new Preview.Builder();
FakePreviewExtender fakePreviewExtender = new FakePreviewExtender(configBuilder,
mockPreviewExtenderImpl);
@@ -147,12 +146,12 @@
new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
fakePreviewExtender.enableExtension(cameraSelector);
- Preview useCase = new Preview(configBuilder.build());
+ Preview useCase = configBuilder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
public void run() {
// To set the update listener and Preview will change to active state.
- useCase.setPreviewSurfaceCallback(
+ useCase.setPreviewSurfaceProvider(
createSurfaceTextureProvider(NO_OP_SURFACE_TEXTURE_CALLBACK));
CameraX.bindToLifecycle(mFakeLifecycle, cameraSelector, useCase);
@@ -216,7 +215,7 @@
when(mockPreviewExtenderImpl.getCaptureStage()).thenReturn(fakeCaptureStageImpl);
- PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+ Preview.Builder configBuilder = new Preview.Builder();
FakePreviewExtender fakePreviewExtender = new FakePreviewExtender(configBuilder,
mockPreviewExtenderImpl);
@@ -224,13 +223,13 @@
new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
fakePreviewExtender.enableExtension(cameraSelector);
- Preview preview = new Preview(configBuilder.build());
+ Preview preview = configBuilder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
public void run() {
// To set the update listener and Preview will change to active state.
- preview.setPreviewSurfaceCallback(
+ preview.setPreviewSurfaceProvider(
createSurfaceTextureProvider(NO_OP_SURFACE_TEXTURE_CALLBACK));
CameraX.bindToLifecycle(mFakeLifecycle, cameraSelector, preview);
@@ -270,18 +269,18 @@
when(mockPreviewExtenderImpl.isExtensionAvailable(any(String.class),
any(CameraCharacteristics.class))).thenReturn(true);
- PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+ Preview.Builder configBuilder = new Preview.Builder();
FakePreviewExtender fakePreviewExtender = new FakePreviewExtender(configBuilder,
mockPreviewExtenderImpl);
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
fakePreviewExtender.enableExtension(cameraSelector);
- Preview preview = new Preview(configBuilder.build());
+ Preview preview = configBuilder.build();
mInstrumentation.runOnMainSync(new Runnable() {
@Override
public void run() {
// To set the update listener and Preview will change to active state.
- preview.setPreviewSurfaceCallback(
+ preview.setPreviewSurfaceProvider(
createSurfaceTextureProvider(NO_OP_SURFACE_TEXTURE_CALLBACK));
CameraX.bindToLifecycle(mFakeLifecycle, cameraSelector, preview);
@@ -301,7 +300,7 @@
assumeTrue(ExtensionVersion.getRuntimeVersion().compareTo(Version.VERSION_1_1) >= 0);
LensFacing lensFacing = CameraX.getDefaultLensFacing();
- PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+ Preview.Builder configBuilder = new Preview.Builder();
PreviewExtenderImpl mockPreviewExtenderImpl = mock(PreviewExtenderImpl.class);
when(mockPreviewExtenderImpl.isExtensionAvailable(any(), any())).thenReturn(true);
@@ -317,14 +316,14 @@
mockPreviewExtenderImpl);
// Checks the config does not include supported resolutions before applying effect mode.
- assertThat(configBuilder.build().getSupportedResolutions(null)).isNull();
+ assertThat(configBuilder.getUseCaseConfig().getSupportedResolutions(null)).isNull();
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(lensFacing).build();
// Checks the config includes supported resolutions after applying effect mode.
fakeExtender.enableExtension(cameraSelector);
List<Pair<Integer, Size[]>> resultFormatResolutionsPairList =
- configBuilder.build().getSupportedResolutions(null);
+ configBuilder.getUseCaseConfig().getSupportedResolutions(null);
assertThat(resultFormatResolutionsPairList).isNotNull();
// Checks the result and target pair lists are the same
@@ -368,7 +367,7 @@
}
private class FakePreviewExtender extends PreviewExtender {
- FakePreviewExtender(PreviewConfig.Builder builder, PreviewExtenderImpl impl) {
+ FakePreviewExtender(Preview.Builder builder, PreviewExtenderImpl impl) {
init(builder, impl, EffectMode.NORMAL);
}
}
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
index 66f4610..fe3303d 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
@@ -153,18 +153,18 @@
}
/**
- * Creates a {@link PreviewConfig.Builder} object for specific {@link EffectMode} and
+ * Creates a {@link Preview.Builder} object for specific {@link EffectMode} and
* {@link LensFacing}.
*
* @param effectMode The effect mode for the created object.
* @param lensFacing The lens facing for the created object.
- * @return A {@link PreviewConfig.Builder} object.
+ * @return A {@link Preview.Builder} object.
*/
@NonNull
- public static PreviewConfig.Builder createPreviewConfigBuilderWithEffect(
+ public static Preview.Builder createPreviewBuilderWithEffect(
@NonNull EffectMode effectMode,
@NonNull LensFacing lensFacing) {
- PreviewConfig.Builder builder = new PreviewConfig.Builder();
+ Preview.Builder builder = new Preview.Builder();
CameraSelector selector =
new CameraSelector.Builder().requireLensFacing(lensFacing).build();
PreviewExtender extender = null;
@@ -211,9 +211,7 @@
@NonNull LensFacing lensFacing) {
ImageCaptureConfig.Builder imageCaptureConfigBuilder =
createImageCaptureConfigBuilderWithEffect(effectMode, lensFacing);
- ImageCaptureConfig imageCaptureConfig = imageCaptureConfigBuilder.build();
-
- return imageCaptureConfig;
+ return imageCaptureConfigBuilder.getUseCaseConfig();
}
/**
@@ -227,11 +225,9 @@
@NonNull
public static PreviewConfig createPreviewConfigWithEffect(@NonNull EffectMode effectMode,
@NonNull LensFacing lensFacing) {
- PreviewConfig.Builder previewConfigBuilder =
- createPreviewConfigBuilderWithEffect(effectMode, lensFacing);
- PreviewConfig previewConfig = previewConfigBuilder.build();
-
- return previewConfig;
+ Preview.Builder previewBuilder =
+ createPreviewBuilderWithEffect(effectMode, lensFacing);
+ return previewBuilder.getUseCaseConfig();
}
/**
@@ -247,9 +243,7 @@
@NonNull LensFacing lensFacing) {
ImageCaptureConfig imageCaptureConfig = createImageCaptureConfigWithEffect(effectMode,
lensFacing);
- ImageCapture imageCapture = new ImageCapture(imageCaptureConfig);
-
- return imageCapture;
+ return new ImageCapture(imageCaptureConfig);
}
/**
@@ -262,10 +256,7 @@
@NonNull
public static Preview createPreviewWithEffect(@NonNull EffectMode effectMode,
@NonNull LensFacing lensFacing) {
- PreviewConfig previewConfig = createPreviewConfigWithEffect(effectMode, lensFacing);
- Preview preview = new Preview(previewConfig);
-
- return preview;
+ return createPreviewBuilderWithEffect(effectMode, lensFacing).build();
}
/**
@@ -368,7 +359,7 @@
* {@link ImageCaptureConfig.Builder}.
*
* @param effectMode The effect mode for the created object.
- * @param builder The {@link ImageCaptureConfig.Builder} for the created object.
+ * @param builder The {@link ImageCaptureConfig.Builder} for the created object.
* @return An {@link ImageCaptureExtender} object.
*/
@NonNull
@@ -400,15 +391,15 @@
/**
* Creates a {@link PreviewExtender} object for specific {@link EffectMode} and
- * {@link PreviewConfig.Builder}.
+ * {@link Preview.Builder}.
*
* @param effectMode The effect mode for the created object.
- * @param builder The {@link PreviewConfig.Builder} for the created object.
+ * @param builder The {@link Preview.Builder} for the created object.
* @return A {@link PreviewExtender} object.
*/
@NonNull
public static PreviewExtender createPreviewExtender(@NonNull EffectMode effectMode,
- @NonNull PreviewConfig.Builder builder) {
+ @NonNull Preview.Builder builder) {
PreviewExtender extender = null;
switch (effectMode) {
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java
index 7dd9894..6ec296b 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java
@@ -20,7 +20,7 @@
import androidx.annotation.NonNull;
import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
import androidx.camera.extensions.ExtensionsManager.EffectMode;
import androidx.camera.extensions.impl.AutoPreviewExtenderImpl;
@@ -34,9 +34,9 @@
* Create a new instance of the auto extender.
*
* @param builder Builder that will be used to create the configurations for the
- * {@link androidx.camera.core.Preview}.
+ * {@link androidx.camera.core.Preview}.
*/
- public static AutoPreviewExtender create(PreviewConfig.Builder builder) {
+ public static AutoPreviewExtender create(Preview.Builder builder) {
if (ExtensionVersion.isExtensionVersionSupported()) {
try {
return new VendorAutoPreviewExtender(builder);
@@ -67,11 +67,12 @@
static class VendorAutoPreviewExtender extends AutoPreviewExtender {
private final AutoPreviewExtenderImpl mImpl;
- VendorAutoPreviewExtender(PreviewConfig.Builder builder) {
+ VendorAutoPreviewExtender(Preview.Builder builder) {
mImpl = new AutoPreviewExtenderImpl();
init(builder, mImpl, EffectMode.AUTO);
}
}
- private AutoPreviewExtender() {}
+ private AutoPreviewExtender() {
+ }
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java
index ab5323a..dcaff72 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java
@@ -20,7 +20,7 @@
import androidx.annotation.NonNull;
import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
import androidx.camera.extensions.ExtensionsManager.EffectMode;
import androidx.camera.extensions.impl.BeautyPreviewExtenderImpl;
@@ -34,9 +34,9 @@
* Create a new instance of the beauty extender.
*
* @param builder Builder that will be used to create the configurations for the
- * {@link androidx.camera.core.Preview}.
+ * {@link androidx.camera.core.Preview}.
*/
- public static BeautyPreviewExtender create(PreviewConfig.Builder builder) {
+ public static BeautyPreviewExtender create(Preview.Builder builder) {
if (ExtensionVersion.isExtensionVersionSupported()) {
try {
return new VendorBeautyPreviewExtender(builder);
@@ -67,11 +67,12 @@
static class VendorBeautyPreviewExtender extends BeautyPreviewExtender {
private final BeautyPreviewExtenderImpl mImpl;
- VendorBeautyPreviewExtender(PreviewConfig.Builder builder) {
+ VendorBeautyPreviewExtender(Preview.Builder builder) {
mImpl = new BeautyPreviewExtenderImpl();
init(builder, mImpl, EffectMode.BEAUTY);
}
}
- private BeautyPreviewExtender() {}
+ private BeautyPreviewExtender() {
+ }
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java
index 26f6892..ccf88a0 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java
@@ -20,7 +20,7 @@
import androidx.annotation.NonNull;
import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
import androidx.camera.extensions.ExtensionsManager.EffectMode;
import androidx.camera.extensions.impl.BokehPreviewExtenderImpl;
@@ -34,9 +34,9 @@
* Create a new instance of the bokeh extender.
*
* @param builder Builder that will be used to create the configurations for the
- * {@link androidx.camera.core.Preview}.
+ * {@link androidx.camera.core.Preview}.
*/
- public static BokehPreviewExtender create(PreviewConfig.Builder builder) {
+ public static BokehPreviewExtender create(Preview.Builder builder) {
if (ExtensionVersion.isExtensionVersionSupported()) {
try {
return new VendorBokehPreviewExtender(builder);
@@ -67,11 +67,12 @@
private static class VendorBokehPreviewExtender extends BokehPreviewExtender {
private final BokehPreviewExtenderImpl mImpl;
- VendorBokehPreviewExtender(PreviewConfig.Builder builder) {
+ VendorBokehPreviewExtender(Preview.Builder builder) {
mImpl = new BokehPreviewExtenderImpl();
init(builder, mImpl, EffectMode.BOKEH);
}
}
- private BokehPreviewExtender() {}
+ private BokehPreviewExtender() {
+ }
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
index 1179b41..e8be743 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
@@ -28,7 +28,6 @@
import androidx.camera.core.ImageCaptureConfig;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.Futures;
import androidx.camera.extensions.impl.InitializerImpl;
@@ -246,7 +245,7 @@
private static boolean checkPreviewExtensionCapability(EffectMode effectMode,
LensFacing lensFacing) {
- PreviewConfig.Builder builder = new PreviewConfig.Builder();
+ Preview.Builder builder = new Preview.Builder();
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(lensFacing).build();
PreviewExtender extender;
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java
index 7bd20a4..cf5be4d 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java
@@ -20,7 +20,7 @@
import androidx.annotation.NonNull;
import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
import androidx.camera.extensions.ExtensionsManager.EffectMode;
import androidx.camera.extensions.impl.HdrPreviewExtenderImpl;
@@ -34,9 +34,9 @@
* Create a new instance of the HDR extender.
*
* @param builder Builder that will be used to create the configurations for the
- * {@link androidx.camera.core.Preview}.
+ * {@link androidx.camera.core.Preview}.
*/
- public static HdrPreviewExtender create(PreviewConfig.Builder builder) {
+ public static HdrPreviewExtender create(Preview.Builder builder) {
if (ExtensionVersion.isExtensionVersionSupported()) {
try {
return new VendorHdrPreviewExtender(builder);
@@ -67,11 +67,12 @@
static class VendorHdrPreviewExtender extends HdrPreviewExtender {
private final HdrPreviewExtenderImpl mImpl;
- VendorHdrPreviewExtender(PreviewConfig.Builder builder) {
+ VendorHdrPreviewExtender(Preview.Builder builder) {
mImpl = new HdrPreviewExtenderImpl();
init(builder, mImpl, EffectMode.HDR);
}
}
- private HdrPreviewExtender() {}
+ private HdrPreviewExtender() {
+ }
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
index dbf36f6..4c9bc4c3 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
@@ -107,7 +107,7 @@
public void enableExtension(@NonNull CameraSelector cameraSelector) {
// Add extension camera id filter to config.
ExtensionCameraIdFilter extensionCameraIdFilter = new ExtensionCameraIdFilter(mImpl);
- CameraIdFilter currentCameraIdFilter = mBuilder.build().getCameraIdFilter(null);
+ CameraIdFilter currentCameraIdFilter = mBuilder.getUseCaseConfig().getCameraIdFilter(null);
CameraSelector.Builder selectorBuilder =
CameraSelector.Builder.fromSelector(cameraSelector);
if (currentCameraIdFilter == null) {
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java
index 166710f..4e5210b 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java
@@ -20,7 +20,7 @@
import androidx.annotation.NonNull;
import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
import androidx.camera.extensions.ExtensionsManager.EffectMode;
import androidx.camera.extensions.impl.NightPreviewExtenderImpl;
@@ -34,9 +34,9 @@
* Create a new instance of the night extender.
*
* @param builder Builder that will be used to create the configurations for the
- * {@link androidx.camera.core.Preview}.
+ * {@link androidx.camera.core.Preview}.
*/
- public static NightPreviewExtender create(PreviewConfig.Builder builder) {
+ public static NightPreviewExtender create(Preview.Builder builder) {
if (ExtensionVersion.isExtensionVersionSupported()) {
try {
return new VendorNightPreviewExtender(builder);
@@ -67,11 +67,12 @@
static class VendorNightPreviewExtender extends NightPreviewExtender {
private final NightPreviewExtenderImpl mImpl;
- VendorNightPreviewExtender(PreviewConfig.Builder builder) {
+ VendorNightPreviewExtender(Preview.Builder builder) {
mImpl = new NightPreviewExtenderImpl();
init(builder, mImpl, EffectMode.NIGHT);
}
}
- private NightPreviewExtender() {}
+ private NightPreviewExtender() {
+ }
}
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
index 7851202..c1e834a 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
@@ -35,7 +35,7 @@
import androidx.camera.core.CaptureConfig;
import androidx.camera.core.Config;
import androidx.camera.core.LensFacing;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
import androidx.camera.core.UseCase;
import androidx.camera.core.impl.utils.CameraSelectorUtil;
import androidx.camera.extensions.ExtensionsErrorListener.ExtensionsErrorCode;
@@ -56,11 +56,11 @@
static final Config.Option<EffectMode> OPTION_PREVIEW_EXTENDER_MODE = Config.Option.create(
"camerax.extensions.previewExtender.mode", EffectMode.class);
- private PreviewConfig.Builder mBuilder;
+ private Preview.Builder mBuilder;
PreviewExtenderImpl mImpl;
private EffectMode mEffectMode;
- void init(PreviewConfig.Builder builder, PreviewExtenderImpl implementation,
+ void init(Preview.Builder builder, PreviewExtenderImpl implementation,
EffectMode effectMode) {
mBuilder = builder;
mImpl = implementation;
@@ -68,12 +68,10 @@
}
/**
- * Indicates whether extension function can support with
- * {@link PreviewConfig.Builder}
+ * Indicates whether extension function can support with {@link Preview.Builder}.
*
* @param cameraSelector The selector that determines a camera that will be checked for the
* availability of extensions.
- *
* @return True if the specific extension function is supported for the camera device.
*/
public boolean isExtensionAvailable(@NonNull CameraSelector cameraSelector) {
@@ -104,7 +102,7 @@
public void enableExtension(@NonNull CameraSelector cameraSelector) {
// Add extension camera id filter to config.
ExtensionCameraIdFilter extensionCameraIdFilter = new ExtensionCameraIdFilter(mImpl);
- CameraIdFilter currentCameraIdFilter = mBuilder.build().getCameraIdFilter(null);
+ CameraIdFilter currentCameraIdFilter = mBuilder.getUseCaseConfig().getCameraIdFilter(null);
CameraSelector.Builder selectorBuilder =
CameraSelector.Builder.fromSelector(cameraSelector);
if (currentCameraIdFilter == null) {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
index a1314daa..e6d9107 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
@@ -89,14 +89,11 @@
}
}
- PreviewConfig config =
- new PreviewConfig.Builder()
- .setTargetName("Preview")
- .build();
-
- mPreview = new Preview(config);
+ mPreview = new Preview.Builder()
+ .setTargetName("Preview")
+ .build();
TextureView textureView = findViewById(R.id.textureView);
- mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+ mPreview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -128,6 +125,7 @@
CameraX.getCameraWithCameraDeviceConfig(
CameraSelectorUtil.toCameraDeviceConfig(cameraSelector));
} catch (CameraInfoUnavailableException e) {
+ final PreviewConfig config = (PreviewConfig) mPreview.getUseCaseConfig();
throw new IllegalArgumentException(
"Unable to get camera id for the camera device config "
+ config.getLensFacing(), e);
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
index 62cb9cf..2e49159 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
@@ -43,7 +43,7 @@
* Creates a new instance of a {@link FakeUseCase} with a default configuration.
*/
public FakeUseCase() {
- this(new FakeUseCaseConfig.Builder().build());
+ this(new FakeUseCaseConfig.Builder().getUseCaseConfig());
}
@Override
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
index e27a164..e55dd98 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
@@ -235,10 +235,16 @@
return mOptionsBundle;
}
+ @NonNull
+ @Override
+ public FakeUseCaseConfig getUseCaseConfig() {
+ return new FakeUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+ }
+
@Override
@NonNull
- public FakeUseCaseConfig build() {
- return new FakeUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+ public FakeUseCase build() {
+ return new FakeUseCase(getUseCaseConfig());
}
// Implementations of TargetConfig.Builder default methods
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java b/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
index 6f8247a..5ac77f3 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
@@ -42,7 +42,6 @@
import androidx.camera.core.MeteringPoint;
import androidx.camera.core.MeteringPointFactory;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.core.PreviewSurfaceProviders;
import androidx.camera.testing.CameraUtil;
import androidx.camera.testing.CoreAppTestUtil;
@@ -200,11 +199,9 @@
}
private void startAndWaitForCameraReady(LensFacing lensFacing) throws InterruptedException {
- PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-
- Preview preview = new Preview(previewConfigBuilder.build());
+ Preview preview = new Preview.Builder().build();
mInstrumentation.runOnMainSync(() -> {
- preview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+ preview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
index c31fafe..b097500 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
@@ -43,7 +43,6 @@
import androidx.camera.core.ImageCaptureConfig;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.core.VideoCapture;
import androidx.camera.core.VideoCapture.OnVideoSavedCallback;
import androidx.camera.core.VideoCaptureConfig;
@@ -61,11 +60,8 @@
import java.io.File;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.LinkedHashSet;
-import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -81,7 +77,7 @@
private static final Rational ASPECT_RATIO_9_16 = new Rational(9, 16);
private static final Rational ASPECT_RATIO_3_4 = new Rational(3, 4);
- private final PreviewConfig.Builder mPreviewConfigBuilder;
+ private final Preview.Builder mPreviewBuilder;
private final VideoCaptureConfig.Builder mVideoCaptureConfigBuilder;
private final ImageCaptureConfig.Builder mImageCaptureConfigBuilder;
private final CameraView mCameraView;
@@ -111,7 +107,7 @@
public void onDestroy(LifecycleOwner owner) {
if (owner == mCurrentLifecycle) {
clearCurrentLifecycle();
- mPreview.setPreviewSurfaceCallback(null);
+ mPreview.setPreviewSurfaceProvider(null);
}
}
};
@@ -123,7 +119,7 @@
CameraXModule(CameraView view) {
this.mCameraView = view;
- mPreviewConfigBuilder = new PreviewConfig.Builder().setTargetName("Preview");
+ mPreviewBuilder = new Preview.Builder().setTargetName("Preview");
mImageCaptureConfigBuilder =
new ImageCaptureConfig.Builder().setTargetName("ImageCapture");
@@ -202,52 +198,33 @@
}
mImageCaptureConfigBuilder.setTargetRotation(getDisplaySurfaceRotation());
- mImageCapture = new ImageCapture(mImageCaptureConfigBuilder.build());
+ mImageCapture = mImageCaptureConfigBuilder.build();
mVideoCaptureConfigBuilder.setTargetRotation(getDisplaySurfaceRotation());
- mVideoCapture = new VideoCapture(mVideoCaptureConfigBuilder.build());
+ mVideoCapture = mVideoCaptureConfigBuilder.build();
// Adjusts the preview resolution according to the view size and the target aspect ratio.
int height = (int) (getMeasuredWidth() / targetAspectRatio.floatValue());
- mPreviewConfigBuilder.setTargetResolution(new Size(getMeasuredWidth(), height));
+ mPreviewBuilder.setTargetResolution(new Size(getMeasuredWidth(), height));
- mPreview = new Preview(mPreviewConfigBuilder.build());
- mPreview.setPreviewSurfaceCallback(new Preview.PreviewSurfaceCallback() {
- // Thread safe because it only accessed on the default executor, which is UI thread.
- Map<Surface, SurfaceTexture> mSurfaceTextureMap = new HashMap<>();
-
- @NonNull
- @Override
- public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
- // The PreviewSurfaceCallback#createSurfaceFuture() might come asynchronously.
+ mPreview = mPreviewBuilder.build();
+ mPreview.setPreviewSurfaceProvider((resolution, safeToCancelFuture) -> {
+ // The PreviewSurfaceProvider#createSurfaceFuture() might come asynchronously.
// It cannot guarantee the callback time, so we store the resolution result in
// the listenableFuture.
mResolutionUpdateCompleter.set(resolution);
- // Create SurfaceTexture and Surface.
- SurfaceTexture surfaceTexture = new SurfaceTexture(0);
- surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
- resolution.getHeight());
- surfaceTexture.detachFromGLContext();
- CameraXModule.this.setSurfaceTexture(surfaceTexture);
- Surface surface = new Surface(surfaceTexture);
- mSurfaceTextureMap.put(surface, surfaceTexture);
- return Futures.immediateFuture(surface);
- }
-
- @Override
- public void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture) {
- try {
- Surface surface = surfaceFuture.get();
- surface.release();
- SurfaceTexture surfaceTexture = mSurfaceTextureMap.get(surface);
- if (surfaceTexture != null) {
- surfaceTexture.release();
- mSurfaceTextureMap.remove(surface);
- }
- } catch (ExecutionException | InterruptedException e) {
- Log.e(TAG, "Failed to release Surface", e);
- }
- }
+ // Create SurfaceTexture and Surface.
+ SurfaceTexture surfaceTexture = new SurfaceTexture(0);
+ surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
+ resolution.getHeight());
+ surfaceTexture.detachFromGLContext();
+ CameraXModule.this.setSurfaceTexture(surfaceTexture);
+ Surface surface = new Surface(surfaceTexture);
+ safeToCancelFuture.addListener(() -> {
+ surface.release();
+ surfaceTexture.release();
+ }, CameraXExecutors.directExecutor());
+ return Futures.immediateFuture(surface);
});
CameraSelector cameraSelector =
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
index 4e2beba..aaee145 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
@@ -116,12 +116,12 @@
}
/**
- * Gets the {@link Preview.PreviewSurfaceCallback} to be used with
- * {@link Preview#setPreviewSurfaceCallback(Executor, Preview.PreviewSurfaceCallback)}.
+ * Gets the {@link Preview.PreviewSurfaceProvider} to be used with
+ * {@link Preview#setPreviewSurfaceProvider(Executor, Preview.PreviewSurfaceProvider)}.
*/
@NonNull
- public Preview.PreviewSurfaceCallback getPreviewSurfaceCallback() {
- return mImplementation.getPreviewSurfaceCallback();
+ public Preview.PreviewSurfaceProvider getPreviewSurfaceProvider() {
+ return mImplementation.getPreviewSurfaceProvider();
}
/**
@@ -137,10 +137,10 @@
void init(@NonNull FrameLayout parent);
/**
- * Gets the {@link Preview.PreviewSurfaceCallback} to be used with {@link Preview}.
+ * Gets the {@link Preview.PreviewSurfaceProvider} to be used with {@link Preview}.
*/
@NonNull
- Preview.PreviewSurfaceCallback getPreviewSurfaceCallback();
+ Preview.PreviewSurfaceProvider getPreviewSurfaceProvider();
}
/**
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java b/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
index d948fa2..dc33f64 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
@@ -46,11 +46,14 @@
final CompleterWithSizeCallback mCompleterWithSizeCallback =
new CompleterWithSizeCallback();
- private Preview.PreviewSurfaceCallback mPreviewSurfaceCallback =
- new Preview.PreviewSurfaceCallback() {
+ private Preview.PreviewSurfaceProvider mPreviewSurfaceProvider =
+ new Preview.PreviewSurfaceProvider() {
@NonNull
@Override
- public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
+ public ListenableFuture<Surface> provideSurface(@NonNull Size resolution,
+ @NonNull ListenableFuture<Void> surfaceReleaseFuture) {
+ // No-op on surfaceReleaseFuture because the Surface will be destroyed by
+ // SurfaceView.
return CallbackToFutureAdapter.getFuture(
completer -> {
// Post to UI thread for thread safety.
@@ -60,11 +63,6 @@
return "SurfaceViewSurfaceCreation";
});
}
-
- @Override
- public void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture) {
- // No-op. The Surface will be released by SurfaceView when it's done.
- }
};
/**
@@ -86,8 +84,8 @@
*/
@NonNull
@Override
- public Preview.PreviewSurfaceCallback getPreviewSurfaceCallback() {
- return mPreviewSurfaceCallback;
+ public Preview.PreviewSurfaceProvider getPreviewSurfaceProvider() {
+ return mPreviewSurfaceProvider;
}
/**
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java b/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java
index 429b5bd..9118358 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java
@@ -54,7 +54,7 @@
@NonNull
@Override
- public Preview.PreviewSurfaceCallback getPreviewSurfaceCallback() {
+ public Preview.PreviewSurfaceProvider getPreviewSurfaceProvider() {
return createSurfaceTextureProvider(new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index 0a738d0..083178b 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -16,8 +16,6 @@
package androidx.camera.integration.core;
-import static androidx.camera.core.PreviewSurfaceProviders.createSurfaceTextureProvider;
-
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -32,14 +30,13 @@
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
-import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -53,13 +50,12 @@
import androidx.camera.core.ImageCaptureConfig;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
-import androidx.camera.core.PreviewSurfaceProviders;
import androidx.camera.core.UseCase;
import androidx.camera.core.VideoCapture;
import androidx.camera.core.VideoCaptureConfig;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.lifecycle.LifecycleCameraProvider;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LiveData;
@@ -68,6 +64,8 @@
import androidx.test.espresso.IdlingResource;
import androidx.test.espresso.idling.CountingIdlingResource;
+import com.google.common.util.concurrent.ListenableFuture;
+
import java.io.File;
import java.math.BigDecimal;
import java.text.Format;
@@ -75,6 +73,7 @@
import java.util.Calendar;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
@@ -119,30 +118,6 @@
// Synthetic Accessor
@SuppressWarnings("WeakerAccess")
TextureView mTextureView;
- private final SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() {
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
-
- }
-
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
-
- }
-
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- return false;
- }
-
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- // Wait until surface texture receives enough updates.
- if (!mViewIdlingResource.isIdleNow()) {
- mViewIdlingResource.decrement();
- }
- }
- };
// Espresso testing variables
@VisibleForTesting
@@ -190,8 +165,7 @@
} else {
// Add the use case
buttonView.setBackgroundColor(Color.LTGRAY);
-
- CameraXActivity.this.enablePreview();
+ enablePreview();
}
}
});
@@ -200,34 +174,20 @@
}
void enablePreview() {
- PreviewConfig config =
- new PreviewConfig.Builder()
- .setTargetName("Preview")
- .build();
-
- mPreview = new Preview(config);
+ mPreview = new Preview.Builder()
+ .setTargetName("Preview")
+ .build();
Log.d(TAG, "enablePreview");
- mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
- new PreviewSurfaceProviders.SurfaceTextureCallback() {
- @Override
- public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
- @NonNull Size resolution) {
- Log.d(TAG, "onSurfaceTextureReady");
- // If TextureView was already created, need to re-add it to change the
- // SurfaceTexture.
- ViewGroup viewGroup = (ViewGroup) mTextureView.getParent();
- viewGroup.removeView(mTextureView);
- viewGroup.addView(mTextureView);
- mTextureView.setSurfaceTexture(surfaceTexture);
- transformPreview(resolution);
- }
- @Override
- public void onSafeToRelease(@NonNull SurfaceTexture surfaceTexture) {
- Log.d(TAG, "onSafeToRelease");
- surfaceTexture.release();
- }
- }));
+ mPreview.setPreviewSurfaceProvider(
+ (resolution, surfaceReleaseFuture) -> CallbackToFutureAdapter.getFuture(
+ completer -> {
+ ((PreviewSurfaceTextureListener) mTextureView
+ .getSurfaceTextureListener())
+ .setSurfaceFutureCompleter(completer,
+ resolution, surfaceReleaseFuture);
+ return "PreviewSurfaceCreation";
+ }));
for (int i = 0; i < FRAMES_UNTIL_VIEW_IS_READY; i++) {
mViewIdlingResource.increment();
@@ -383,12 +343,9 @@
}
void enableImageAnalysis() {
- ImageAnalysisConfig config =
- new ImageAnalysisConfig.Builder()
- .setTargetName("ImageAnalysis")
- .build();
-
- mImageAnalysis = new ImageAnalysis(config);
+ mImageAnalysis = new ImageAnalysisConfig.Builder()
+ .setTargetName("ImageAnalysis")
+ .build();
TextView textView = this.findViewById(R.id.textView);
mAnalysisIdlingResource.increment();
@@ -459,13 +416,10 @@
}
void enableImageCapture() {
- ImageCaptureConfig config =
- new ImageCaptureConfig.Builder()
- .setCaptureMode(mCaptureMode)
- .setTargetName("ImageCapture")
- .build();
-
- mImageCapture = new ImageCapture(config);
+ mImageCapture = new ImageCaptureConfig.Builder()
+ .setCaptureMode(mCaptureMode)
+ .setTargetName("ImageCapture")
+ .build();
Camera camera = bindToLifecycleSafely(mImageCapture, R.id.PhotoToggle);
if (camera == null) {
@@ -641,12 +595,9 @@
}
void enableVideoCapture() {
- VideoCaptureConfig config =
- new VideoCaptureConfig.Builder()
- .setTargetName("VideoCapture")
- .build();
-
- mVideoCapture = new VideoCapture(config);
+ mVideoCapture = new VideoCaptureConfig.Builder()
+ .setTargetName("VideoCapture")
+ .build();
if (bindToLifecycleSafely(mVideoCapture, R.id.VideoToggle) == null) {
Button button = this.findViewById(R.id.Video);
@@ -702,7 +653,7 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_xmain);
mTextureView = findViewById(R.id.textureView);
- mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+ mTextureView.setSurfaceTextureListener(new PreviewSurfaceTextureListener());
StrictMode.VmPolicy policy =
new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build();
@@ -919,4 +870,112 @@
VideoCapture getVideoCapture() {
return mVideoCapture;
}
+
+ /**
+ * Manages the life cycle of the {@link TextureView} {@link SurfaceTexture} for {@link Preview}
+ * use cases.
+ *
+ * This class is responsible for resolving two race conditions: the creation
+ * and the destroy of the {@link Surface}/{@link SurfaceTexture} pair.
+ */
+ final class PreviewSurfaceTextureListener implements
+ TextureView.SurfaceTextureListener {
+
+ @GuardedBy("this")
+ CallbackToFutureAdapter.Completer<Surface> mSurfaceCompleter;
+ @GuardedBy("this")
+ Size mResolution;
+ @GuardedBy("this")
+ SurfaceTexture mSurfaceTexture;
+ @GuardedBy("this")
+ ListenableFuture<Void> mSurfaceSafeToReleaseFuture;
+
+ // Whether the handle is still being used by the consumer(TextureView).
+ AtomicBoolean mIsSurfaceTextureUsedByTextureView = new AtomicBoolean(true);
+ // Whether the handle is still being used by the producer(CameraX).
+ AtomicBoolean mIsSurfaceTextureUsedByPreview = new AtomicBoolean(false);
+
+ /**
+ * Resolves the race condition in {@link SurfaceTexture} creation.
+ */
+ private synchronized void tryToSetSurface() {
+ if (mResolution != null && mSurfaceTexture != null && mSurfaceCompleter != null) {
+ Log.d(TAG, "SurfaceTexture set " + hashCode());
+ // Only set Surface when both the consumer and the producer are ready.
+ mSurfaceTexture.setDefaultBufferSize(mResolution.getWidth(),
+ mResolution.getHeight());
+ final Surface surface = new Surface(mSurfaceTexture);
+ mSurfaceCompleter.set(surface);
+ mIsSurfaceTextureUsedByPreview.set(true);
+
+ mSurfaceSafeToReleaseFuture.addListener(() -> {
+ Log.d(TAG, "Preview is ready to release Surface." + hashCode());
+ surface.release();
+ mIsSurfaceTextureUsedByPreview.set(false);
+ tryToReleaseSurfaceTexture();
+ }, ContextCompat.getMainExecutor(CameraXActivity.this));
+ }
+ }
+
+ /**
+ * Resolves the race condition in {@link SurfaceTexture} releasing.
+ */
+ private synchronized void tryToReleaseSurfaceTexture() {
+ if (!mIsSurfaceTextureUsedByTextureView.get()
+ && !mIsSurfaceTextureUsedByPreview.get()
+ && mSurfaceTexture != null) {
+ Log.d(TAG, "SurfaceTexture released " + hashCode());
+ // Only release when both the consumer and the producer are done.
+ mSurfaceTexture.release();
+ mSurfaceTexture = null;
+ }
+ }
+
+ synchronized void setSurfaceFutureCompleter(
+ CallbackToFutureAdapter.Completer<Surface> surfaceCompleter,
+ Size resolution,
+ ListenableFuture<Void> surfaceSafeToReleaseFuture) {
+ Log.d(TAG, "SurfaceCompleter set. " + hashCode());
+ mSurfaceCompleter = surfaceCompleter;
+ mResolution = resolution;
+ mSurfaceSafeToReleaseFuture = surfaceSafeToReleaseFuture;
+ transformPreview(resolution);
+ tryToSetSurface();
+ }
+
+ @Override
+ public synchronized void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
+ int height) {
+ Log.d(TAG, "TextureView is ready to set SurfaceTexture. " + hashCode());
+ mSurfaceTexture = surfaceTexture;
+ mIsSurfaceTextureUsedByTextureView.set(true);
+ tryToSetSurface();
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
+ int height) {
+ Log.d(TAG, "onSurfaceTextureSizeChanged " + width + "x" + height);
+ // No-op.
+ }
+
+ @Override
+ public synchronized boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ Log.d(TAG, "TextureView is ready to release SurfaceTexture. " + hashCode());
+ mIsSurfaceTextureUsedByTextureView.set(false);
+ ContextCompat.getMainExecutor(CameraXActivity.this).execute(
+ this::tryToReleaseSurfaceTexture);
+ // Never auto release. Premature releasing causes CaptureSession to misbehave on LEGACY
+ // devices. Wait for CameraX's signal to release it.
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ // Wait until surface texture receives enough updates. This is for testing.
+ if (!mViewIdlingResource.isIdleNow()) {
+ mViewIdlingResource.decrement();
+ }
+ }
+ }
}
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java
index d501648..dbc9f23 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java
@@ -109,7 +109,7 @@
SurfaceTexture.OnFrameAvailableListener mOnFrameAvailableListener;
private ImageCaptureConfig.Builder mImageCaptureConfigBuilder;
- private PreviewConfig.Builder mPreviewConfigBuilder;
+ private Preview.Builder mPreviewBuilder;
private ImageAnalysisConfig.Builder mImageAnalysisConfigBuilder;
@Parameterized.Parameters
@@ -147,7 +147,7 @@
mLifecycleOwner = new FakeLifecycleOwner();
mImageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
- mPreviewConfigBuilder = new PreviewConfig.Builder();
+ mPreviewBuilder = new Preview.Builder();
mImageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
mCameraStatusCallback = new CameraDevice.StateCallback() {
@Override
@@ -237,19 +237,18 @@
enableExtension(mEffectMode, mLensFacing);
// To test bind/unbind and take picture.
- ImageCapture imageCapture = new ImageCapture(mImageCaptureConfigBuilder.build());
+ ImageCapture imageCapture = mImageCaptureConfigBuilder.build();
- PreviewConfig previewConfig = mPreviewConfigBuilder
- .build();
+ PreviewConfig previewConfig = mPreviewBuilder.getUseCaseConfig();
CaptureProcessor previewCaptureProcessor = previewConfig.getCaptureProcessor(null);
assumeNotNull(previewCaptureProcessor);
- mPreviewConfigBuilder.setCaptureProcessor(
+ mPreviewBuilder.setCaptureProcessor(
new TimestampCaptureProcessor(previewCaptureProcessor, mTimestampListener));
- Preview preview = new Preview(mPreviewConfigBuilder.build());
+ Preview preview = mPreviewBuilder.build();
// To set the update listener and Preview will change to active state.
- preview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+ preview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -296,25 +295,25 @@
switch (effectMode) {
case HDR:
imageCaptureExtender = HdrImageCaptureExtender.create(mImageCaptureConfigBuilder);
- previewExtender = HdrPreviewExtender.create(mPreviewConfigBuilder);
+ previewExtender = HdrPreviewExtender.create(mPreviewBuilder);
break;
case BOKEH:
imageCaptureExtender = BokehImageCaptureExtender.create(
mImageCaptureConfigBuilder);
- previewExtender = BokehPreviewExtender.create(mPreviewConfigBuilder);
+ previewExtender = BokehPreviewExtender.create(mPreviewBuilder);
break;
case BEAUTY:
imageCaptureExtender = BeautyImageCaptureExtender.create(
mImageCaptureConfigBuilder);
- previewExtender = BeautyPreviewExtender.create(mPreviewConfigBuilder);
+ previewExtender = BeautyPreviewExtender.create(mPreviewBuilder);
break;
case NIGHT:
imageCaptureExtender = NightImageCaptureExtender.create(mImageCaptureConfigBuilder);
- previewExtender = NightPreviewExtender.create(mPreviewConfigBuilder);
+ previewExtender = NightPreviewExtender.create(mPreviewBuilder);
break;
case AUTO:
imageCaptureExtender = AutoImageCaptureExtender.create(mImageCaptureConfigBuilder);
- previewExtender = AutoPreviewExtender.create(mPreviewConfigBuilder);
+ previewExtender = AutoPreviewExtender.create(mPreviewBuilder);
break;
}
diff --git a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
index d70d733..22e2470 100644
--- a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
+++ b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
@@ -44,7 +44,6 @@
import androidx.camera.core.ImageCaptureConfig;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.core.PreviewSurfaceProviders;
import androidx.camera.core.UseCase;
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
@@ -124,9 +123,8 @@
LifecycleCameraProvider.unbind(mPreview);
}
- PreviewConfig.Builder builder =
- new PreviewConfig.Builder()
- .setTargetName("Preview");
+ Preview.Builder builder = new Preview.Builder()
+ .setTargetName("Preview");
Log.d(TAG, "Enabling the extended preview");
if (mCurrentImageCaptureType == ImageCaptureType.IMAGE_CAPTURE_TYPE_BOKEH) {
@@ -166,8 +164,8 @@
}
}
- mPreview = new Preview(builder.build());
- mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+ mPreview = builder.build();
+ mPreview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
new PreviewSurfaceProviders.SurfaceTextureCallback() {
@Override
public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -301,7 +299,7 @@
return;
}
- mImageCapture = new ImageCapture(builder.build());
+ mImageCapture = builder.build();
Button captureButton = findViewById(R.id.Picture);
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt
index e2bc6af..2e6c59d 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt
@@ -24,18 +24,18 @@
import android.os.Handler
import android.os.HandlerThread
import android.util.Size
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureConfig
+import androidx.camera.core.Preview
import androidx.camera.integration.antelope.MainActivity.Companion.FIXED_FOCUS_DISTANCE
import androidx.camera.integration.antelope.MainActivity.Companion.INVALID_FOCAL_LENGTH
import androidx.camera.integration.antelope.MainActivity.Companion.NO_APERTURE
-import androidx.camera.core.ImageCapture
-import androidx.camera.core.ImageCaptureConfig
-import androidx.camera.core.PreviewConfig
import androidx.camera.integration.antelope.cameracontrollers.Camera2CaptureSessionCallback
import androidx.camera.integration.antelope.cameracontrollers.Camera2DeviceStateCallback
import androidx.camera.integration.antelope.cameracontrollers.CameraState
+import androidx.camera.integration.antelope.cameracontrollers.CameraXCaptureSessionCallback
import androidx.camera.integration.antelope.cameracontrollers.CameraXDeviceStateCallback
import androidx.camera.integration.antelope.cameracontrollers.CameraXPreviewSessionStateCallback
-import androidx.camera.integration.antelope.cameracontrollers.CameraXCaptureSessionCallback
/**
* CameraParams contains a list of device characteristics for a given camera device.
@@ -104,15 +104,12 @@
internal var cameraXDeviceStateCallback: CameraXDeviceStateCallback? = null
internal var cameraXPreviewSessionStateCallback: CameraXPreviewSessionStateCallback? = null
internal var cameraXCaptureSessionCallback: CameraXCaptureSessionCallback? = null
- internal var cameraXPreviewConfig: PreviewConfig =
- PreviewConfig.Builder().build()
- internal var cameraXCaptureConfig: ImageCaptureConfig =
- ImageCaptureConfig.Builder().build()
+ internal var cameraXPreviewBuilder: Preview.Builder = Preview.Builder()
+ internal var cameraXCaptureBuilder: ImageCaptureConfig.Builder = ImageCaptureConfig.Builder()
// Custom lifecycle for CameraX API
internal var cameraXLifecycle: CustomLifecycle = CustomLifecycle()
- internal var cameraXImageCaptureUseCase: ImageCapture =
- ImageCapture(ImageCaptureConfig.Builder().build())
+ internal var cameraXImageCaptureUseCase: ImageCapture = ImageCaptureConfig.Builder().build()
// Testing variables
internal var timer: CameraTimer = CameraTimer()
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
index 159071f..ab919f2 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
@@ -30,7 +30,7 @@
import android.view.Surface
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.ImageCaptureConfig
-import androidx.camera.core.PreviewConfig
+import androidx.camera.core.Preview
import androidx.camera.integration.antelope.MainActivity.Companion.FIXED_FOCUS_DISTANCE
import androidx.camera.integration.antelope.MainActivity.Companion.cameraParams
import androidx.camera.integration.antelope.MainActivity.Companion.logd
@@ -165,9 +165,9 @@
previewSurfaceView = activity.surface_preview
cameraXPreviewTexture = activity.texture_preview
- cameraXPreviewConfig = PreviewConfig.Builder().build()
+ cameraXPreviewBuilder = Preview.Builder()
- cameraXCaptureConfig = ImageCaptureConfig.Builder().build()
+ cameraXCaptureBuilder = ImageCaptureConfig.Builder()
imageAvailableListener =
ImageAvailableListener(activity, this, TestConfig())
@@ -220,10 +220,13 @@
params.cam2MinSize
params.imageReader?.close()
- params.imageReader = ImageReader.newInstance(size.width, size.height,
- ImageFormat.JPEG, 5)
+ params.imageReader = ImageReader.newInstance(
+ size.width, size.height,
+ ImageFormat.JPEG, 5
+ )
params.imageReader?.setOnImageAvailableListener(
- params.imageAvailableListener, params.backgroundHandler)
+ params.imageAvailableListener, params.backgroundHandler
+ )
}
}
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt
index c8b4df9..705ce10 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt
@@ -24,14 +24,12 @@
import android.view.ViewGroup
import androidx.annotation.experimental.UseExperimental
import androidx.camera.camera2.Camera2Config
-
import androidx.camera.camera2.ExperimentalCamera2Interop
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureConfig
import androidx.camera.core.LensFacing
import androidx.camera.core.Preview
-import androidx.camera.core.PreviewConfig
import androidx.camera.core.PreviewSurfaceProviders
import androidx.camera.core.PreviewSurfaceProviders.createSurfaceTextureProvider
import androidx.camera.core.impl.utils.executor.CameraXExecutors
@@ -69,7 +67,8 @@
// Currently we swap out the ids behind the scenes
// This requires to save the actual camera id for after the test
if ((testConfig.currentRunningTest == TestType.SWITCH_CAMERA) ||
- (testConfig.currentRunningTest == TestType.MULTI_SWITCH)) {
+ (testConfig.currentRunningTest == TestType.MULTI_SWITCH)
+ ) {
testConfig.switchTestRealCameraId = params.id // Save the actual camera ID
params.id = testConfig.switchTestCurrentCamera
}
@@ -79,12 +78,14 @@
CameraXPreviewSessionStateCallback(activity, params, testConfig)
if (params.cameraXDeviceStateCallback != null &&
- params.cameraXPreviewSessionStateCallback != null) {
- params.cameraXPreviewConfig =
+ params.cameraXPreviewSessionStateCallback != null
+ ) {
+ params.cameraXPreviewBuilder =
cameraXPreviewUseCaseBuilder(
testConfig.focusMode,
params.cameraXDeviceStateCallback!!,
- params.cameraXPreviewSessionStateCallback!!)
+ params.cameraXPreviewSessionStateCallback!!
+ )
}
if (!params.cameraXLifecycle.isFinished()) {
@@ -95,11 +96,11 @@
params.cameraXLifecycle = CustomLifecycle()
val lifecycleOwner: LifecycleOwner = params.cameraXLifecycle
- val previewUseCase = Preview(params.cameraXPreviewConfig)
+ val previewUseCase = params.cameraXPreviewBuilder.build()
// Set preview to observe the surface texture
activity.runOnUiThread {
- previewUseCase.previewSurfaceCallback = createSurfaceTextureProvider(
+ previewUseCase.previewSurfaceProvider = createSurfaceTextureProvider(
object : PreviewSurfaceProviders.SurfaceTextureCallback {
override fun onSafeToRelease(surfaceTexture: SurfaceTexture) {
@@ -144,15 +145,17 @@
CameraXCaptureSessionCallback(activity, params, testConfig)
if (params.cameraXDeviceStateCallback != null &&
- params.cameraXCaptureSessionCallback != null) {
- params.cameraXCaptureConfig =
+ params.cameraXCaptureSessionCallback != null
+ ) {
+ params.cameraXCaptureBuilder =
cameraXImageCaptureUseCaseBuilder(
testConfig.focusMode,
params.cameraXDeviceStateCallback!!,
- params.cameraXCaptureSessionCallback!!)
+ params.cameraXCaptureSessionCallback!!
+ )
}
- params.cameraXImageCaptureUseCase = ImageCapture(params.cameraXCaptureConfig)
+ params.cameraXImageCaptureUseCase = params.cameraXCaptureBuilder.build()
params.timer.openStart = System.currentTimeMillis()
@@ -189,7 +192,8 @@
}
}
if ((testConfig.currentRunningTest == TestType.SWITCH_CAMERA) ||
- (testConfig.currentRunningTest == TestType.MULTI_SWITCH)) {
+ (testConfig.currentRunningTest == TestType.MULTI_SWITCH)
+ ) {
params.id = testConfig.switchTestRealCameraId // Restore the actual camera ID
}
@@ -212,8 +216,10 @@
logd("CameraX TakePicture: capture start.")
// Pause in multi-captures to make sure HDR routines don't get overloaded
- logd("CameraX TakePicture. Pausing for " +
- PrefHelper.getPreviewBuffer(activity) + "ms to let preview run.")
+ logd(
+ "CameraX TakePicture. Pausing for " +
+ PrefHelper.getPreviewBuffer(activity) + "ms to let preview run."
+ )
params.timer.previewFillStart = System.currentTimeMillis()
Thread.sleep(PrefHelper.getPreviewBuffer(activity))
@@ -287,9 +293,9 @@
focusMode: FocusMode,
deviceStateCallback: CameraDevice.StateCallback,
sessionCaptureStateCallback: CameraCaptureSession.StateCallback
-): PreviewConfig {
+): Preview.Builder {
- val configBuilder = PreviewConfig.Builder()
+ val configBuilder = Preview.Builder()
Camera2Config.Extender(configBuilder)
.setDeviceStateCallback(deviceStateCallback)
.setSessionStateCallback(sessionCaptureStateCallback)
@@ -297,7 +303,7 @@
// Prints a log to suppress "fix Parameter 'focusMode' is never used" build error"
Log.d("Antelope", "focusMode($focusMode) Not enabled.")
- return configBuilder.build()
+ return configBuilder
}
/**
@@ -309,7 +315,7 @@
deviceStateCallback:
CameraDevice.StateCallback,
sessionCaptureCallback: CameraCaptureSession.CaptureCallback
-): ImageCaptureConfig {
+): ImageCaptureConfig.Builder {
val configBuilder = ImageCaptureConfig.Builder()
.setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
@@ -320,5 +326,5 @@
// Prints a log to suppress "fix Parameter 'focusMode' is never used" build error"
Log.d("Antelope", "focusMode($focusMode) Not enabled.")
- return configBuilder.build()
+ return configBuilder
}
\ No newline at end of file
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java
index a86e658b..db6d7c5 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java
@@ -27,7 +27,6 @@
import androidx.camera.core.CameraSelector;
import androidx.camera.core.LensFacing;
import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
import androidx.camera.lifecycle.LifecycleCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.fragment.app.Fragment;
@@ -68,10 +67,11 @@
}
private void bindPreview() {
- Preview preview = new Preview(new PreviewConfig.Builder()
+ Preview preview = new Preview.Builder()
.setTargetName("Preview")
- .build());
- preview.setPreviewSurfaceCallback(mPreviewView.getPreviewSurfaceCallback());
+ .build();
+
+ preview.setPreviewSurfaceProvider(mPreviewView.getPreviewSurfaceProvider());
CameraSelector cameraSelector =
new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
diff --git a/compose/compose-ide-plugin/build.gradle b/compose/compose-ide-plugin/build.gradle
index 4eb00cb..f909b50 100644
--- a/compose/compose-ide-plugin/build.gradle
+++ b/compose/compose-ide-plugin/build.gradle
@@ -23,12 +23,19 @@
import static androidx.build.dependencies.DependenciesKt.*
+buildscript {
+ dependencies {
+ classpath("gradle.plugin.org.jetbrains.intellij.plugins:gradle-intellij-plugin:0.4.8")
+ }
+}
+
plugins {
id("AndroidXPlugin")
id("kotlin")
- id("org.jetbrains.intellij") version("0.4.8")
}
+apply(plugin: "org.jetbrains.intellij")
+
def studioWrapper = StudioWrapper.create(rootProject)
// Unfortunately the Intellij plugin requires libs from the Studio installation as soon as it is
diff --git a/core/core/api/1.3.0-alpha01.txt b/core/core/api/1.3.0-alpha01.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/1.3.0-alpha01.txt
+++ b/core/core/api/1.3.0-alpha01.txt
@@ -462,29 +462,29 @@
method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
method @ColorInt public int getColor();
method public android.graphics.Bitmap! getLargeIcon();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
- method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
}
- public static class NotificationCompat.CarExtender.UnreadConversation {
- method public long getLatestTimestamp();
- method public String![]! getMessages();
- method public String! getParticipant();
- method public String![]! getParticipants();
- method public android.app.PendingIntent! getReadPendingIntent();
- method public androidx.core.app.RemoteInput! getRemoteInput();
- method public android.app.PendingIntent! getReplyPendingIntent();
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]! getMessages();
+ method @Deprecated public String! getParticipant();
+ method @Deprecated public String![]! getParticipants();
+ method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+ method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
}
- public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
- ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
}
public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -462,29 +462,29 @@
method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
method @ColorInt public int getColor();
method public android.graphics.Bitmap! getLargeIcon();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
- method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
}
- public static class NotificationCompat.CarExtender.UnreadConversation {
- method public long getLatestTimestamp();
- method public String![]! getMessages();
- method public String! getParticipant();
- method public String![]! getParticipants();
- method public android.app.PendingIntent! getReadPendingIntent();
- method public androidx.core.app.RemoteInput! getRemoteInput();
- method public android.app.PendingIntent! getReplyPendingIntent();
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]! getMessages();
+ method @Deprecated public String! getParticipant();
+ method @Deprecated public String![]! getParticipants();
+ method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+ method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
}
- public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
- ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
}
public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/public_plus_experimental_1.3.0-alpha01.txt b/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
+++ b/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
@@ -462,29 +462,29 @@
method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
method @ColorInt public int getColor();
method public android.graphics.Bitmap! getLargeIcon();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
- method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
}
- public static class NotificationCompat.CarExtender.UnreadConversation {
- method public long getLatestTimestamp();
- method public String![]! getMessages();
- method public String! getParticipant();
- method public String![]! getParticipants();
- method public android.app.PendingIntent! getReadPendingIntent();
- method public androidx.core.app.RemoteInput! getRemoteInput();
- method public android.app.PendingIntent! getReplyPendingIntent();
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]! getMessages();
+ method @Deprecated public String! getParticipant();
+ method @Deprecated public String![]! getParticipants();
+ method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+ method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
}
- public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
- ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
}
public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -462,29 +462,29 @@
method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
method @ColorInt public int getColor();
method public android.graphics.Bitmap! getLargeIcon();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
- method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
}
- public static class NotificationCompat.CarExtender.UnreadConversation {
- method public long getLatestTimestamp();
- method public String![]! getMessages();
- method public String! getParticipant();
- method public String![]! getParticipants();
- method public android.app.PendingIntent! getReadPendingIntent();
- method public androidx.core.app.RemoteInput! getRemoteInput();
- method public android.app.PendingIntent! getReplyPendingIntent();
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]! getMessages();
+ method @Deprecated public String! getParticipant();
+ method @Deprecated public String![]! getParticipants();
+ method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+ method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
}
- public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
- ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
}
public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/restricted_1.3.0-alpha01.txt b/core/core/api/restricted_1.3.0-alpha01.txt
index 70760bb..f86b271 100644
--- a/core/core/api/restricted_1.3.0-alpha01.txt
+++ b/core/core/api/restricted_1.3.0-alpha01.txt
@@ -519,29 +519,29 @@
method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
method @ColorInt public int getColor();
method public android.graphics.Bitmap! getLargeIcon();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
- method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
}
- public static class NotificationCompat.CarExtender.UnreadConversation {
- method public long getLatestTimestamp();
- method public String![]! getMessages();
- method public String! getParticipant();
- method public String![]! getParticipants();
- method public android.app.PendingIntent! getReadPendingIntent();
- method public androidx.core.app.RemoteInput! getRemoteInput();
- method public android.app.PendingIntent! getReplyPendingIntent();
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]! getMessages();
+ method @Deprecated public String! getParticipant();
+ method @Deprecated public String![]! getParticipants();
+ method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+ method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
}
- public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
- ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
}
public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 70760bb..f86b271 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -519,29 +519,29 @@
method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
method @ColorInt public int getColor();
method public android.graphics.Bitmap! getLargeIcon();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
- method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
}
- public static class NotificationCompat.CarExtender.UnreadConversation {
- method public long getLatestTimestamp();
- method public String![]! getMessages();
- method public String! getParticipant();
- method public String![]! getParticipants();
- method public android.app.PendingIntent! getReadPendingIntent();
- method public androidx.core.app.RemoteInput! getRemoteInput();
- method public android.app.PendingIntent! getReplyPendingIntent();
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+ method @Deprecated public long getLatestTimestamp();
+ method @Deprecated public String![]! getMessages();
+ method @Deprecated public String! getParticipant();
+ method @Deprecated public String![]! getParticipants();
+ method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+ method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+ method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
}
- public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
- ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
- method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+ @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+ ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+ method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
}
public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index fb71fc8..f24995f 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -5179,7 +5179,11 @@
*
* @param unreadConversation The unread part of the conversation this notification conveys.
* @return This object for method chaining.
+ *
+ * @deprecated {@link UnreadConversation} is no longer supported. Use {@link MessagingStyle}
+ * instead.
*/
+ @Deprecated
public CarExtender setUnreadConversation(UnreadConversation unreadConversation) {
mUnreadConversation = unreadConversation;
return this;
@@ -5188,14 +5192,22 @@
/**
* Returns the unread conversation conveyed by this notification.
* @see #setUnreadConversation(UnreadConversation)
+ *
+ * @deprecated {@link UnreadConversation} is no longer supported. Use {@link MessagingStyle}
+ * instead.
*/
+ @Deprecated
public UnreadConversation getUnreadConversation() {
return mUnreadConversation;
}
/**
* A class which holds the unread messages from a conversation.
+ *
+ * @deprecated {@link UnreadConversation} is no longer supported. Use {@link MessagingStyle}
+ * instead.
*/
+ @Deprecated
public static class UnreadConversation {
private final String[] mMessages;
private final RemoteInput mRemoteInput;
diff --git a/exifinterface/api/1.2.0-alpha01.txt b/exifinterface/api/1.2.0-alpha01.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/1.2.0-alpha01.txt
+++ b/exifinterface/api/1.2.0-alpha01.txt
@@ -6,9 +6,9 @@
ctor public ExifInterface(String) throws java.io.IOException;
ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
method public void flipHorizontally();
method public void flipVertically();
- method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public String? getAttribute(String);
method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
field public static final short SHARPNESS_HARD = 2; // 0x2
field public static final short SHARPNESS_NORMAL = 0; // 0x0
field public static final short SHARPNESS_SOFT = 1; // 0x1
+ field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+ field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/current.txt b/exifinterface/api/current.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/current.txt
+++ b/exifinterface/api/current.txt
@@ -6,9 +6,9 @@
ctor public ExifInterface(String) throws java.io.IOException;
ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
method public void flipHorizontally();
method public void flipVertically();
- method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public String? getAttribute(String);
method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
field public static final short SHARPNESS_HARD = 2; // 0x2
field public static final short SHARPNESS_NORMAL = 0; // 0x0
field public static final short SHARPNESS_SOFT = 1; // 0x1
+ field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+ field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt b/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt
+++ b/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt
@@ -6,9 +6,9 @@
ctor public ExifInterface(String) throws java.io.IOException;
ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
method public void flipHorizontally();
method public void flipVertically();
- method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public String? getAttribute(String);
method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
field public static final short SHARPNESS_HARD = 2; // 0x2
field public static final short SHARPNESS_NORMAL = 0; // 0x0
field public static final short SHARPNESS_SOFT = 1; // 0x1
+ field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+ field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/public_plus_experimental_current.txt b/exifinterface/api/public_plus_experimental_current.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/public_plus_experimental_current.txt
+++ b/exifinterface/api/public_plus_experimental_current.txt
@@ -6,9 +6,9 @@
ctor public ExifInterface(String) throws java.io.IOException;
ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
method public void flipHorizontally();
method public void flipVertically();
- method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public String? getAttribute(String);
method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
field public static final short SHARPNESS_HARD = 2; // 0x2
field public static final short SHARPNESS_NORMAL = 0; // 0x0
field public static final short SHARPNESS_SOFT = 1; // 0x1
+ field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+ field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/restricted_1.2.0-alpha01.txt b/exifinterface/api/restricted_1.2.0-alpha01.txt
index 8c8bca9..5aacfe0 100644
--- a/exifinterface/api/restricted_1.2.0-alpha01.txt
+++ b/exifinterface/api/restricted_1.2.0-alpha01.txt
@@ -6,9 +6,9 @@
ctor public ExifInterface(String) throws java.io.IOException;
ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream, @androidx.exifinterface.media.ExifInterface.ExifStreamType int) throws java.io.IOException;
method public void flipHorizontally();
method public void flipVertically();
- method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public String? getAttribute(String);
method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
field public static final short SHARPNESS_HARD = 2; // 0x2
field public static final short SHARPNESS_NORMAL = 0; // 0x0
field public static final short SHARPNESS_SOFT = 1; // 0x1
+ field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+ field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
@@ -342,5 +344,6 @@
}
+
}
diff --git a/exifinterface/api/restricted_current.txt b/exifinterface/api/restricted_current.txt
index 8c8bca9..5aacfe0 100644
--- a/exifinterface/api/restricted_current.txt
+++ b/exifinterface/api/restricted_current.txt
@@ -6,9 +6,9 @@
ctor public ExifInterface(String) throws java.io.IOException;
ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+ ctor public ExifInterface(java.io.InputStream, @androidx.exifinterface.media.ExifInterface.ExifStreamType int) throws java.io.IOException;
method public void flipHorizontally();
method public void flipVertically();
- method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
method public double getAltitude(double);
method public String? getAttribute(String);
method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
field public static final short SHARPNESS_HARD = 2; // 0x2
field public static final short SHARPNESS_NORMAL = 0; // 0x0
field public static final short SHARPNESS_SOFT = 1; // 0x1
+ field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+ field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
@@ -342,5 +344,6 @@
}
+
}
diff --git a/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java b/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
index a6526cd..a06d992 100644
--- a/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
+++ b/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
@@ -28,6 +28,7 @@
import android.Manifest;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.location.Location;
import android.os.Build;
import android.os.Environment;
@@ -261,8 +262,13 @@
public final float longitude;
public final float altitude;
- // Values.
+ // Make information
+ public final boolean hasMake;
+ public final int makeOffset;
+ public final int makeLength;
public final String make;
+
+ // Values.
public final String model;
public final float aperture;
public final String dateTimeOriginal;
@@ -316,8 +322,13 @@
longitude = typedArray.getFloat(index++, 0f);
altitude = typedArray.getFloat(index++, 0f);
- // Reads values.
+ // Reads Make information.
+ hasMake = typedArray.getBoolean(index++, false);
+ makeOffset = typedArray.getInt(index++, -1);
+ makeLength = typedArray.getInt(index++, -1);
make = getString(typedArray, index++);
+
+ // Reads values.
model = getString(typedArray, index++);
aperture = typedArray.getFloat(index++, 0f);
dateTimeOriginal = getString(typedArray, index++);
@@ -821,14 +832,7 @@
assertEquals(expectedValue.thumbnailOffset, thumbnailRange[0]);
assertEquals(expectedValue.thumbnailLength, thumbnailRange[1]);
}
- byte[] thumbnailBytes = exifInterface.getThumbnailBytes();
- assertNotNull(thumbnailBytes);
- Bitmap thumbnailBitmap = exifInterface.getThumbnailBitmap();
- assertNotNull(thumbnailBitmap);
- assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
- assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
- assertEquals(expectedValue.isThumbnailCompressed,
- exifInterface.isThumbnailCompressed());
+ testThumbnail(expectedValue, exifInterface);
} else {
assertNull(exifInterface.getThumbnailRange());
assertNull(exifInterface.getThumbnail());
@@ -856,6 +860,23 @@
}
assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
+ // Checks Make information.
+ String make = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+ assertEquals(expectedValue.hasMake, make != null);
+ if (expectedValue.hasMake) {
+ assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_MAKE));
+ if (assertRanges) {
+ final long[] makeRange = exifInterface
+ .getAttributeRange(ExifInterface.TAG_MAKE);
+ assertEquals(expectedValue.makeOffset, makeRange[0]);
+ assertEquals(expectedValue.makeLength, makeRange[1]);
+ }
+ assertEquals(expectedValue.make, make);
+ } else {
+ assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_MAKE));
+ assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_MAKE));
+ }
+
// Checks values.
assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
@@ -923,7 +944,8 @@
fis.read(exifBytes);
ByteArrayInputStream bin = new ByteArrayInputStream(exifBytes);
- ExifInterface exifInterface = ExifInterface.fromStandalone(bin);
+ ExifInterface exifInterface =
+ new ExifInterface(bin, ExifInterface.STREAM_TYPE_EXIF_DATA_ONLY);
compareWithExpectedValue(exifInterface, expectedValue, verboseTag, true);
}
@@ -968,6 +990,60 @@
}
}
+ private void testExifInterfaceRange(String fileName, ExpectedValue expectedValue)
+ throws IOException {
+ File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+ InputStream in = null;
+ try {
+ in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+ if (expectedValue.hasThumbnail) {
+ in.skip(expectedValue.thumbnailOffset);
+ byte[] thumbnailBytes = new byte[expectedValue.thumbnailLength];
+ if (in.read(thumbnailBytes) != expectedValue.thumbnailLength) {
+ throw new IOException("Failed to read the expected thumbnail length");
+ }
+ // TODO: Need a way to check uncompressed thumbnail file
+ Bitmap thumbnailBitmap = BitmapFactory.decodeByteArray(thumbnailBytes, 0,
+ thumbnailBytes.length);
+ assertNotNull(thumbnailBitmap);
+ assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+ assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
+ }
+
+ // TODO: Creating a new input stream is a temporary
+ // workaround for BufferedInputStream#mark/reset not working properly for
+ // LG_G4_ISO_800_DNG. Need to investigate cause.
+ in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+ if (expectedValue.hasMake) {
+ in.skip(expectedValue.makeOffset);
+ byte[] makeBytes = new byte[expectedValue.makeLength];
+ if (in.read(makeBytes) != expectedValue.makeLength) {
+ throw new IOException("Failed to read the expected make length");
+ }
+ String makeString = new String(makeBytes);
+ // Remove null bytes
+ makeString = makeString.replaceAll("\u0000.*", "");
+ assertEquals(expectedValue.make, makeString);
+ }
+
+ in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+ if (expectedValue.hasXmp) {
+ in.skip(expectedValue.xmpOffset);
+ byte[] identifierBytes = new byte[expectedValue.xmpLength];
+ if (in.read(identifierBytes) != expectedValue.xmpLength) {
+ throw new IOException("Failed to read the expected xmp length");
+ }
+ final String xmpIdentifier = "<?xpacket begin=";
+ assertTrue(new String(identifierBytes, Charset.forName("UTF-8"))
+ .startsWith(xmpIdentifier));
+ }
+ // TODO: Add code for retrieving raw latitude data using offset and length
+ } finally {
+ closeQuietly(in);
+ }
+ }
+
private void testSaveAttributes_withFileName(String fileName, ExpectedValue expectedValue)
throws IOException {
File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
@@ -976,15 +1052,23 @@
ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
exifInterface.saveAttributes();
exifInterface = new ExifInterface(imageFile.getAbsolutePath());
-
compareWithExpectedValue(exifInterface, expectedValue, verboseTag, false);
// Test for modifying one attribute.
String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
exifInterface.saveAttributes();
+ // Check if thumbnail offset and length are properly updated without parsing the data again.
+ if (expectedValue.hasThumbnail) {
+ testThumbnail(expectedValue, exifInterface);
+ }
exifInterface = new ExifInterface(imageFile.getAbsolutePath());
assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+ // Check if thumbnail bytes can be retrieved from the new thumbnail range.
+ if (expectedValue.hasThumbnail) {
+ testThumbnail(expectedValue, exifInterface);
+ }
+
// Restore the backup value.
exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
exifInterface.saveAttributes();
@@ -1000,6 +1084,9 @@
// Test for reading from external data storage.
testExifInterfaceCommon(fileName, expectedValue);
+ // Test for checking expected range by retrieving raw data with given offset and length.
+ testExifInterfaceRange(fileName, expectedValue);
+
// Test for saving attributes.
testSaveAttributes_withFileName(fileName, expectedValue);
}
@@ -1012,8 +1099,18 @@
// Test for reading from external data storage.
testExifInterfaceCommon(fileName, expectedValue);
- // Since ExifInterface does not support for saving attributes for non-JPEG files, do not
- // test about writing back in here.
+ // Test for checking expected range by retrieving raw data with given offset and length.
+ testExifInterfaceRange(fileName, expectedValue);
+ }
+
+ private void testThumbnail(ExpectedValue expectedValue, ExifInterface exifInterface) {
+ byte[] thumbnail = exifInterface.getThumbnail();
+ assertNotNull(thumbnail);
+ Bitmap thumbnailBitmap = BitmapFactory.decodeByteArray(thumbnail, 0,
+ thumbnail.length);
+ assertNotNull(thumbnailBitmap);
+ assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+ assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
}
private void generateRandomExifTag(ByteBuffer buffer, int ifdType, Random random) {
diff --git a/exifinterface/src/androidTest/res/values/arrays.xml b/exifinterface/src/androidTest/res/values/arrays.xml
index 58af04b..d828bad 100644
--- a/exifinterface/src/androidTest/res/values/arrays.xml
+++ b/exifinterface/src/androidTest/res/values/arrays.xml
@@ -16,18 +16,24 @@
<resources>
<array name="exifbyteorderii_jpg">
+ <!--Whether thumbnail exists-->
<item>true</item>
<item>3500</item>
<item>6265</item>
<item>512</item>
<item>288</item>
<item>true</item>
+ <!--Whether GPS LatLong information exists-->
<item>false</item>
<item>0</item>
<item>0</item>
<item>0.0</item>
<item>0.0</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>160</item>
+ <item>8</item>
<item>SAMSUNG</item>
<item>SM-N900S</item>
<item>2.200</item>
@@ -54,18 +60,24 @@
<item>0</item>
</array>
<array name="exifbyteorderii_standalone">
+ <!--Whether thumbnail exists-->
<item>true</item>
<item>3494</item>
<item>6265</item>
<item>512</item>
<item>288</item>
<item>true</item>
+ <!--Whether GPS LatLong information exists-->
<item>false</item>
<item>0</item>
<item>0</item>
<item>0.0</item>
<item>0.0</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>154</item>
+ <item>8</item>
<item>SAMSUNG</item>
<item>SM-N900S</item>
<item>2.200</item>
@@ -92,18 +104,24 @@
<item>0</item>
</array>
<array name="exifbyteordermm_jpg">
+ <!--Whether thumbnail exists-->
<item>false</item>
<item>0</item>
<item>0</item>
<item>0</item>
<item>0</item>
<item>false</item>
+ <!--Whether GPS LatLong information exists-->
<item>true</item>
- <item>572</item>
+ <item>584</item>
<item>24</item>
<item>0.0</item>
<item>0.0</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>414</item>
+ <item>4</item>
<item>LGE</item>
<item>Nexus 5</item>
<item>2.400</item>
@@ -130,18 +148,24 @@
<item>0</item>
</array>
<array name="exifbyteordermm_standalone">
+ <!--Whether thumbnail exists-->
<item>false</item>
<item>0</item>
<item>0</item>
<item>0</item>
<item>0</item>
<item>false</item>
+ <!--Whether GPS LatLong information exists-->
<item>true</item>
- <item>572</item>
+ <item>578</item>
<item>24</item>
<item>0.0</item>
<item>0.0</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>408</item>
+ <item>4</item>
<item>LGE</item>
<item>Nexus 5</item>
<item>2.400</item>
@@ -168,18 +192,24 @@
<item>0</item>
</array>
<array name="lg_g4_iso_800_dng">
+ <!--Whether thumbnail exists-->
<item>true</item>
- <item>0</item>
+ <item>12570</item>
<item>15179</item>
<item>256</item>
<item>144</item>
<item>true</item>
+ <!--Whether GPS LatLong information exists-->
<item>true</item>
<item>12486</item>
<item>24</item>
<item>53.834507</item>
<item>10.69585</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>102</item>
+ <item>4</item>
<item>LGE</item>
<item>LG-H815</item>
<item>1.800</item>
@@ -206,18 +236,24 @@
<item>10067</item>
</array>
<array name="lg_g4_iso_800_jpg">
+ <!--Whether thumbnail exists-->
<item>false</item>
<item>0</item>
<item>0</item>
<item>0</item>
<item>0</item>
<item>false</item>
+ <!--Whether GPS LatLong information exists-->
<item>true</item>
- <item>1662</item>
+ <item>1692</item>
<item>24</item>
<item>53.834507</item>
<item>10.69585</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>84</item>
+ <item>4</item>
<item>LGE</item>
<item>LG-H815</item>
<item>1.800</item>
@@ -244,18 +280,24 @@
<item>13197</item>
</array>
<array name="exifbyteorderii_png">
+ <!--Whether thumbnail exists-->
<item>true</item>
<item>212271</item>
<item>6265</item>
<item>512</item>
<item>288</item>
<item>true</item>
+ <!--Whether GPS LatLong information exists-->
<item>false</item>
<item>0</item>
<item>0</item>
<item>0.0</item>
<item>0.0</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>211525</item>
+ <item>8</item>
<item>SAMSUNG</item>
<item>SM-N900S</item>
<item>2.200</item>
@@ -282,18 +324,24 @@
<item>0</item>
</array>
<array name="exifbyteorderii_webp">
+ <!--Whether thumbnail exists-->
<item>true</item>
<item>9646</item>
<item>6265</item>
<item>512</item>
<item>288</item>
<item>true</item>
+ <!--Whether GPS LatLong information exists-->
<item>false</item>
<item>0</item>
<item>0</item>
<item>0.0</item>
<item>0.0</item>
<item>0.0</item>
+ <!--Whether Make information exists-->
+ <item>true</item>
+ <item>6306</item>
+ <item>8</item>
<item>SAMSUNG</item>
<item>SM-N900S</item>
<item>2.200</item>
diff --git a/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java b/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
index 0e1eacc..02e41f7 100644
--- a/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
+++ b/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
@@ -2908,6 +2908,27 @@
*/
public static final int REDUCED_RESOLUTION_IMAGE = 1;
+ /**
+ * Constant used to indicate that the input stream contains the full image data.
+ * <p>
+ * The format of the image data should follow one of the image formats supported by this class.
+ */
+ public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0;
+ /**
+ * Constant used to indicate that the input stream contains only Exif data.
+ * <p>
+ * The format of the Exif-only data must follow the below structure:
+ * Exif Identifier Code ("Exif\0\0") + TIFF header + IFD data
+ * See JEITA CP-3451C Section 4.5.2 and 4.5.4 specifications for more details.
+ */
+ public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1;
+
+ /** @hide */
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({STREAM_TYPE_FULL_IMAGE_DATA, STREAM_TYPE_EXIF_DATA_ONLY})
+ public @interface ExifStreamType {}
+
// Maximum size for checking file type signature (see image_type_recognition_lite.cc)
private static final int SIGNATURE_CHECK_SIZE = 5000;
@@ -3830,13 +3851,15 @@
private FileDescriptor mSeekableFileDescriptor;
private AssetManager.AssetInputStream mAssetInputStream;
private int mMimeType;
- private boolean mIsStandalone;
+ private boolean mIsExifDataOnly;
@SuppressWarnings("unchecked")
private final HashMap<String, ExifAttribute>[] mAttributes = new HashMap[EXIF_TAGS.length];
private Set<Integer> mAttributesOffsets = new HashSet<>(EXIF_TAGS.length);
private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
private boolean mHasThumbnail;
- // The following values used for indicating a thumbnail position.
+ private boolean mHasThumbnailStrips;
+ private boolean mAreThumbnailStripsConsecutive;
+ // Used to indicate the position of the thumbnail (includes offset to EXIF data segment).
private int mThumbnailOffset;
private int mThumbnailLength;
private byte[] mThumbnailBytes;
@@ -3857,6 +3880,11 @@
/**
* Reads Exif tags from the specified image file.
+ *
+ * @param file the file of the image data
+ * @throws NullPointerException if file is null
+ * @throws IOException if an I/O error occurs while retrieving file descriptor via
+ * {@link FileInputStream#getFD()}.
*/
public ExifInterface(@NonNull File file) throws IOException {
if (file == null) {
@@ -3867,6 +3895,11 @@
/**
* Reads Exif tags from the specified image file.
+ *
+ * @param filename the name of the file of the image data
+ * @throws NullPointerException if file name is null
+ * @throws IOException if an I/O error occurs while retrieving file descriptor via
+ * {@link FileInputStream#getFD()}.
*/
public ExifInterface(@NonNull String filename) throws IOException {
if (filename == null) {
@@ -3879,6 +3912,11 @@
* Reads Exif tags from the specified image file descriptor. Attribute mutation is supported
* for writable and seekable file descriptors only. This constructor will not rewind the offset
* of the given file descriptor. Developers should close the file descriptor after use.
+ *
+ * @param fileDescriptor the file descriptor of the image data
+ * @throws NullPointerException if file descriptor is null
+ * @throws IOException if an error occurs while duplicating the file descriptor via
+ * {@link Os#dup(FileDescriptor)}.
*/
public ExifInterface(@NonNull FileDescriptor fileDescriptor) throws IOException {
if (fileDescriptor == null) {
@@ -3919,44 +3957,45 @@
* for input streams. The given input stream will proceed from its current position. Developers
* should close the input stream after use. This constructor is not intended to be used with
* an input stream that performs any networking operations.
+ *
+ * @param inputStream the input stream that contains the image data
+ * @throws NullPointerException if the input stream is null
*/
public ExifInterface(@NonNull InputStream inputStream) throws IOException {
this(inputStream, false);
}
/**
- * Reads Exif tags from the specified standalone input stream. Standalone data refers to Exif
- * data that exists by itself and is not contained in a file format such as jpeg or png.
- * The format of the standalone data must follow the below structure:
- * Exif Identifier Code ("Exif\0\0") + TIFF header + IFD data
- * See JEITA CP-3451C Section 4.5.2 and 4.5.4 specifications for more details.
- * <p>
- * Attribute mutation is not supported for this constructor. The given input stream will proceed
- * from its current position. Developers should close the input stream after use. This
- * constructor is not intended to be used with an input stream that performs any networking
- * operations.
+ * Reads Exif tags from the specified image input stream based on the stream type. Attribute
+ * mutation is not supported for input streams. The given input stream will proceed from its
+ * current position. Developers should close the input stream after use. This constructor is not
+ * intended to be used with an input stream that performs any networking operations.
*
- * @throws IOException if the data does not follow the aforementioned structure.
+ * @param inputStream the input stream that contains the image data
+ * @param streamType the type of input stream
+ * @throws NullPointerException if the input stream is null
+ * @throws IOException if an I/O error occurs while retrieving file descriptor via
+ * {@link FileInputStream#getFD()}.
*/
- @NonNull
- public static ExifInterface fromStandalone(@NonNull InputStream inputStream)
+ public ExifInterface(@NonNull InputStream inputStream, @ExifStreamType int streamType)
throws IOException {
- if (isStandalone(inputStream)) {
- return new ExifInterface(inputStream, true);
- }
- throw new IOException("Given data does not follow the structure of a standalone exif "
- + "data.");
+ this(inputStream, (streamType == STREAM_TYPE_EXIF_DATA_ONLY) ? true : false);
}
- private ExifInterface(@NonNull InputStream inputStream, boolean isFromStandalone)
+ private ExifInterface(@NonNull InputStream inputStream, boolean shouldBeExifDataOnly)
throws IOException {
if (inputStream == null) {
throw new NullPointerException("inputStream cannot be null");
}
mFilename = null;
- if (isFromStandalone) {
- mIsStandalone = true;
+ if (shouldBeExifDataOnly) {
+ inputStream = new BufferedInputStream(inputStream, SIGNATURE_CHECK_SIZE);
+ if (!isExifDataOnly((BufferedInputStream) inputStream)) {
+ Log.w(TAG, "Given data does not follow the structure of an Exif-only data.");
+ return;
+ }
+ mIsExifDataOnly = true;
mAssetInputStream = null;
mSeekableFileDescriptor = null;
} else {
@@ -4462,10 +4501,9 @@
/**
* This function decides which parser to read the image data according to the given input stream
- * type and the content of the input stream. In each case, it reads the first three bytes to
- * determine whether the image data format is JPEG or not.
+ * type and the content of the input stream.
*/
- private void loadAttributes(@NonNull InputStream in) throws IOException {
+ private void loadAttributes(@NonNull InputStream in) {
if (in == null) {
throw new NullPointerException("inputstream shouldn't be null");
}
@@ -4476,7 +4514,7 @@
}
// Check file type
- if (!mIsStandalone) {
+ if (!mIsExifDataOnly) {
in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE);
mMimeType = getMimeType((BufferedInputStream) in);
}
@@ -4484,7 +4522,7 @@
// Create byte-ordered input stream
ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in);
- if (!mIsStandalone) {
+ if (!mIsExifDataOnly) {
switch (mMimeType) {
case IMAGE_TYPE_JPEG: {
getJpegAttributes(inputStream, 0, IFD_TYPE_PRIMARY); // 0 is offset
@@ -4553,12 +4591,15 @@
}
}
- private static boolean isSeekableFD(FileDescriptor fd) throws IOException {
+ private static boolean isSeekableFD(FileDescriptor fd) {
if (Build.VERSION.SDK_INT >= 21) {
try {
Os.lseek(fd, 0, OsConstants.SEEK_CUR);
return true;
} catch (Exception e) {
+ if (DEBUG) {
+ Log.d(TAG, "The file descriptor for the given input is not seekable");
+ }
return false;
}
}
@@ -4744,6 +4785,7 @@
// Should not be reached this.
throw new FileNotFoundException();
}
+
if (in.skip(mThumbnailOffset) != mThumbnailOffset) {
throw new IOException("Corrupted image");
}
@@ -4818,10 +4860,12 @@
/**
* Returns the offset and length of thumbnail inside the image file, or
- * {@code null} if there is no thumbnail.
+ * {@code null} if either there is no thumbnail or the thumbnail bytes are stored
+ * non-consecutively.
*
* @return two-element array, the offset in the first value, and length in
- * the second, or {@code null} if no thumbnail was found.
+ * the second, or {@code null} if no thumbnail was found or the thumbnail strips are
+ * not placed consecutively.
* @throws IllegalStateException if {@link #saveAttributes()} has been
* called since the underlying file was initially parsed, since
* that means offsets may have changed.
@@ -4834,13 +4878,12 @@
}
if (mHasThumbnail) {
- if (mIsStandalone) {
- return new long[] { mThumbnailOffset + mExifOffset, mThumbnailLength };
+ if (mHasThumbnailStrips && !mAreThumbnailStripsConsecutive) {
+ return null;
}
return new long[] { mThumbnailOffset, mThumbnailLength };
- } else {
- return null;
}
+ return null;
}
/**
@@ -5393,10 +5436,11 @@
return true;
}
- private static boolean isStandalone(InputStream inputStream) throws IOException {
+ private static boolean isExifDataOnly(BufferedInputStream in) throws IOException {
+ in.mark(IDENTIFIER_EXIF_APP1.length);
byte[] signatureCheckBytes = new byte[IDENTIFIER_EXIF_APP1.length];
- inputStream.read(signatureCheckBytes);
-
+ in.read(signatureCheckBytes);
+ in.reset();
for (int i = 0; i < IDENTIFIER_EXIF_APP1.length; i++) {
if (signatureCheckBytes[i] != IDENTIFIER_EXIF_APP1[i]) {
return false;
@@ -5476,10 +5520,9 @@
final int offset = start + IDENTIFIER_EXIF_APP1.length;
final byte[] value = Arrays.copyOfRange(bytes, IDENTIFIER_EXIF_APP1.length,
bytes.length);
+ // Save offset values for handling thumbnail and attribute offsets.
+ mExifOffset = offset;
readExifSegment(value, imageType);
-
- // Save offset values for handleThumbnailFromJfif() function
- mExifOffset = (int) offset;
} else if (startsWith(bytes, IDENTIFIER_XMP_APP1)) {
// See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6
final int offset = start + IDENTIFIER_XMP_APP1.length;
@@ -5796,6 +5839,8 @@
if (in.read(bytes) != length) {
throw new IOException("Can't read exif");
}
+ // Save offset values for handling thumbnail and attribute offsets.
+ mExifOffset = offset;
readExifSegment(bytes, IFD_TYPE_PRIMARY);
}
@@ -5808,13 +5853,13 @@
}
private void getStandaloneAttributes(ByteOrderedDataInputStream in) throws IOException {
+ in.skipBytes(IDENTIFIER_EXIF_APP1.length);
// TODO: Need to handle potential OutOfMemoryError
byte[] data = new byte[in.available()];
in.readFully(data);
- readExifSegment(data, IFD_TYPE_PRIMARY);
-
- // Save offset values for handleThumbnailFromJfif() function
+ // Save offset values for handling thumbnail and attribute offsets.
mExifOffset = IDENTIFIER_EXIF_APP1.length;
+ readExifSegment(data, IFD_TYPE_PRIMARY);
}
/**
@@ -5999,13 +6044,11 @@
+ "\n recorded CRC value: " + dataCrcValue + ", calculated CRC "
+ "value: " + crc.getValue());
}
-
+ // Save offset values for handling thumbnail and attribute offsets.
+ mExifOffset = bytesRead;
readExifSegment(data, IFD_TYPE_PRIMARY);
validateImages();
-
- // Save offset values for handleThumbnailFromJfif() function
- mExifOffset = bytesRead;
break;
} else {
// Skip to next chunk
@@ -6065,6 +6108,8 @@
throw new IOException("Failed to read given length for given PNG chunk "
+ "type: " + byteArrayToHexString(code));
}
+ // Save offset values for handling thumbnail and attribute offsets.
+ mExifOffset = bytesRead;
readExifSegment(payload, IFD_TYPE_PRIMARY);
break;
} else {
@@ -6087,8 +6132,6 @@
bytesRead += skipped;
}
}
- // Save offset values for handleThumbnailFromJfif() function
- mExifOffset = bytesRead;
} catch (EOFException e) {
// Should not reach here. Will only reach here if the file is corrupted or
// does not follow the WebP specifications
@@ -6119,7 +6162,7 @@
// Write EXIF APP1 segment
dataOutputStream.writeByte(MARKER);
dataOutputStream.writeByte(MARKER_APP1);
- writeExifSegment(dataOutputStream, 6);
+ writeExifSegment(dataOutputStream);
byte[] bytes = new byte[4096];
@@ -6243,7 +6286,7 @@
ByteOrder.BIG_ENDIAN);
// Store Exif data in separate byte array
- writeExifSegment(exifDataOutputStream, 0);
+ writeExifSegment(exifDataOutputStream);
byte[] exifBytes =
((ByteArrayOutputStream) exifDataOutputStream.mOutputStream).toByteArray();
@@ -6526,7 +6569,7 @@
continue;
}
- final int bytesOffset = dataInputStream.peek();
+ final int bytesOffset = dataInputStream.peek() + mExifOffset;
final byte[] bytes = new byte[(int) byteCount];
dataInputStream.readFully(bytes);
ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents,
@@ -6657,40 +6700,32 @@
int thumbnailOffset = jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
- switch (mMimeType) {
- case IMAGE_TYPE_JPEG:
- case IMAGE_TYPE_RAF:
- case IMAGE_TYPE_RW2:
- case IMAGE_TYPE_PNG:
- case IMAGE_TYPE_WEBP:
- thumbnailOffset += mExifOffset;
- break;
- case IMAGE_TYPE_ORF:
- // Update offset value since RAF files have IFD data preceding MakerNote data.
- thumbnailOffset += mOrfMakerNoteOffset;
- break;
+ if (mMimeType == IMAGE_TYPE_ORF) {
+ // Update offset value since RAF files have IFD data preceding MakerNote data.
+ thumbnailOffset += mOrfMakerNoteOffset;
}
// The following code limits the size of thumbnail size not to overflow EXIF data area.
thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
- if (DEBUG) {
- Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
- + ", length: " + thumbnailLength);
- }
if (thumbnailOffset > 0 && thumbnailLength > 0) {
mHasThumbnail = true;
- mThumbnailOffset = thumbnailOffset;
+ // Need to add mExifOffset, which is the offset to the EXIF data segment
+ mThumbnailOffset = thumbnailOffset + mExifOffset;
mThumbnailLength = thumbnailLength;
if (mFilename == null && mAssetInputStream == null
&& mSeekableFileDescriptor == null) {
// TODO: Need to handle potential OutOfMemoryError
// Save the thumbnail in memory if the input doesn't support reading again.
- byte[] thumbnailBytes = new byte[thumbnailLength];
- in.seek(thumbnailOffset);
+ byte[] thumbnailBytes = new byte[mThumbnailLength];
+ in.seek(mThumbnailOffset);
in.readFully(thumbnailBytes);
mThumbnailBytes = thumbnailBytes;
}
}
+ if (DEBUG) {
+ Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
+ + ", length: " + thumbnailLength);
+ }
}
}
@@ -6708,12 +6743,16 @@
long[] stripByteCounts =
convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
- if (stripOffsets == null) {
- Log.w(TAG, "stripOffsets should not be null.");
+ if (stripOffsets == null || stripOffsets.length == 0) {
+ Log.w(TAG, "stripOffsets should not be null or have zero length.");
return;
}
- if (stripByteCounts == null) {
- Log.w(TAG, "stripByteCounts should not be null.");
+ if (stripByteCounts == null || stripByteCounts.length == 0) {
+ Log.w(TAG, "stripByteCounts should not be null or have zero length.");
+ return;
+ }
+ if (stripOffsets.length != stripByteCounts.length) {
+ Log.w(TAG, "stripOffsets and stripByteCounts should have same length.");
return;
}
@@ -6728,10 +6767,18 @@
int bytesRead = 0;
int bytesAdded = 0;
+ mHasThumbnail = mHasThumbnailStrips = mAreThumbnailStripsConsecutive = true;
for (int i = 0; i < stripOffsets.length; i++) {
int stripOffset = (int) stripOffsets[i];
int stripByteCount = (int) stripByteCounts[i];
+ // Check if strips are consecutive
+ // TODO: Add test for non-consecutive thumbnail image
+ if (i < stripOffsets.length - 1
+ && stripOffset + stripByteCount != stripOffsets[i + 1]) {
+ mAreThumbnailStripsConsecutive = false;
+ }
+
// Skip to offset
int skipBytes = stripOffset - bytesRead;
if (skipBytes < 0) {
@@ -6751,10 +6798,13 @@
stripBytes.length);
bytesAdded += stripBytes.length;
}
-
- mHasThumbnail = true;
mThumbnailBytes = totalStripBytes;
- mThumbnailLength = totalStripBytes.length;
+
+ if (mAreThumbnailStripsConsecutive) {
+ // Need to add mExifOffset, which is the offset to the EXIF data segment
+ mThumbnailOffset = (int) stripOffsets[0] + mExifOffset;
+ mThumbnailLength = totalStripBytes.length;
+ }
}
}
@@ -6922,8 +6972,7 @@
}
// Writes an Exif segment into the given output stream.
- private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream,
- int exifOffsetFromBeginning) throws IOException {
+ private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream) throws IOException {
// The following variables are for calculating each IFD tag group size in bytes.
int[] ifdOffsets = new int[EXIF_TAGS.length];
int[] ifdDataSizes = new int[EXIF_TAGS.length];
@@ -6982,7 +7031,9 @@
}
// Calculate IFD offsets.
- int position = 8; // 8 bytes are for TIFF headers
+ // 8 bytes are for TIFF headers: 2 bytes (byte order) + 2 bytes (identifier) + 4 bytes
+ // (offset of IFDs)
+ int position = 8;
for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
if (!mAttributes[ifdType].isEmpty()) {
ifdOffsets[ifdType] = position;
@@ -6993,7 +7044,8 @@
int thumbnailOffset = position;
mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
- mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
+ // Need to add mExifOffset, which is the offset to the EXIF data segment
+ mThumbnailOffset = thumbnailOffset + mExifOffset;
position += mThumbnailLength;
}
diff --git a/fragment/fragment/api/1.3.0-alpha01.txt b/fragment/fragment/api/1.3.0-alpha01.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/1.3.0-alpha01.txt
+++ b/fragment/fragment/api/1.3.0-alpha01.txt
@@ -49,7 +49,7 @@
method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
method public Object? getReenterTransition();
method public final android.content.res.Resources getResources();
- method public final boolean getRetainInstance();
+ method @Deprecated public final boolean getRetainInstance();
method public Object? getReturnTransition();
method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
method public void setMenuVisibility(boolean);
method public void setReenterTransition(Object?);
- method public void setRetainInstance(boolean);
+ method @Deprecated public void setRetainInstance(boolean);
method public void setReturnTransition(Object?);
method public void setSharedElementEnterTransition(Object?);
method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -49,7 +49,7 @@
method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
method public Object? getReenterTransition();
method public final android.content.res.Resources getResources();
- method public final boolean getRetainInstance();
+ method @Deprecated public final boolean getRetainInstance();
method public Object? getReturnTransition();
method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
method public void setMenuVisibility(boolean);
method public void setReenterTransition(Object?);
- method public void setRetainInstance(boolean);
+ method @Deprecated public void setRetainInstance(boolean);
method public void setReturnTransition(Object?);
method public void setSharedElementEnterTransition(Object?);
method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt b/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt
+++ b/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt
@@ -49,7 +49,7 @@
method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
method public Object? getReenterTransition();
method public final android.content.res.Resources getResources();
- method public final boolean getRetainInstance();
+ method @Deprecated public final boolean getRetainInstance();
method public Object? getReturnTransition();
method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
method public void setMenuVisibility(boolean);
method public void setReenterTransition(Object?);
- method public void setRetainInstance(boolean);
+ method @Deprecated public void setRetainInstance(boolean);
method public void setReturnTransition(Object?);
method public void setSharedElementEnterTransition(Object?);
method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/public_plus_experimental_current.txt b/fragment/fragment/api/public_plus_experimental_current.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/public_plus_experimental_current.txt
+++ b/fragment/fragment/api/public_plus_experimental_current.txt
@@ -49,7 +49,7 @@
method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
method public Object? getReenterTransition();
method public final android.content.res.Resources getResources();
- method public final boolean getRetainInstance();
+ method @Deprecated public final boolean getRetainInstance();
method public Object? getReturnTransition();
method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
method public void setMenuVisibility(boolean);
method public void setReenterTransition(Object?);
- method public void setRetainInstance(boolean);
+ method @Deprecated public void setRetainInstance(boolean);
method public void setReturnTransition(Object?);
method public void setSharedElementEnterTransition(Object?);
method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/restricted_1.3.0-alpha01.txt b/fragment/fragment/api/restricted_1.3.0-alpha01.txt
index 190a2f2..d4e2d2f 100644
--- a/fragment/fragment/api/restricted_1.3.0-alpha01.txt
+++ b/fragment/fragment/api/restricted_1.3.0-alpha01.txt
@@ -51,7 +51,7 @@
method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
method public Object? getReenterTransition();
method public final android.content.res.Resources getResources();
- method public final boolean getRetainInstance();
+ method @Deprecated public final boolean getRetainInstance();
method public Object? getReturnTransition();
method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
method public Object? getSharedElementEnterTransition();
@@ -138,7 +138,7 @@
method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
method public void setMenuVisibility(boolean);
method public void setReenterTransition(Object?);
- method public void setRetainInstance(boolean);
+ method @Deprecated public void setRetainInstance(boolean);
method public void setReturnTransition(Object?);
method public void setSharedElementEnterTransition(Object?);
method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index 190a2f2..d4e2d2f 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -51,7 +51,7 @@
method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
method public Object? getReenterTransition();
method public final android.content.res.Resources getResources();
- method public final boolean getRetainInstance();
+ method @Deprecated public final boolean getRetainInstance();
method public Object? getReturnTransition();
method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
method public Object? getSharedElementEnterTransition();
@@ -138,7 +138,7 @@
method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
method public void setMenuVisibility(boolean);
method public void setReenterTransition(Object?);
- method public void setRetainInstance(boolean);
+ method @Deprecated public void setRetainInstance(boolean);
method public void setReturnTransition(Object?);
method public void setSharedElementEnterTransition(Object?);
method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
index c845318..81251da 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
@@ -48,6 +48,7 @@
}
object Retained : LeakConfiguration() {
+ @Suppress("DEPRECATION")
override fun commit(fragmentManager: FragmentManager) = StrictFragment().apply {
retainInstance = true
}.also {
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt
index 73bd524..cb6ced7 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt
@@ -517,6 +517,66 @@
.that(viewLifecycleOwner.lifecycle.currentState).isEqualTo(Lifecycle.State.DESTROYED)
}
+ /**
+ * Test to ensure childFragment gets initState() called when parent is destroyed
+ */
+ @Test
+ @UiThreadTest
+ fun childFragmentInitWhenFragmentManagerDestroyed() {
+ val viewModelStore = ViewModelStore()
+ val fc = activityRule.startupFragmentController(viewModelStore)
+ val fm = fc.supportFragmentManager
+
+ val fragment = StrictViewFragment(R.layout.simple_container)
+ fm.beginTransaction()
+ .add(android.R.id.content, fragment)
+ .commitNow()
+
+ val childFragment = StrictViewFragment()
+
+ fragment.childFragmentManager.beginTransaction()
+ .add(R.id.fragmentContainer, childFragment, "child")
+ .commitNow()
+
+ val lifecycle = childFragment.lifecycle
+
+ fc.restart(activityRule, viewModelStore, false)
+
+ assertWithMessage("ChildFragment lifecycle instance is same")
+ .that(lifecycle).isNotSameInstanceAs(childFragment.lifecycle)
+ }
+
+ /**
+ * Test to ensure childFragment gets initState() called when parent is removed
+ */
+ @Test
+ @UiThreadTest
+ fun childFragmentInitWhenParentRemoved() {
+ val viewModelStore = ViewModelStore()
+ val fc = activityRule.startupFragmentController(viewModelStore)
+ val fm = fc.supportFragmentManager
+
+ val fragment = StrictViewFragment(R.layout.simple_container)
+ fm.beginTransaction()
+ .add(android.R.id.content, fragment)
+ .commitNow()
+
+ val childFragment = StrictViewFragment()
+
+ fragment.childFragmentManager.beginTransaction()
+ .add(R.id.fragmentContainer, childFragment, "child")
+ .commitNow()
+
+ val lifecycle = childFragment.lifecycle
+
+ fm.beginTransaction()
+ .remove(fragment)
+ .commitNow()
+
+ assertWithMessage("ChildFragment lifecycle instance is same")
+ .that(lifecycle).isNotSameInstanceAs(childFragment.lifecycle)
+ }
+
@Test
@UiThreadTest
fun testSetArgumentsLifecycle() {
@@ -561,6 +621,7 @@
* Ensure that FragmentManager rejects commit() and commitNow() prior to restoring
* saved instance state
*/
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun addRetainedBeforeRestoreSaveState() {
@@ -601,6 +662,7 @@
/**
* Ensure that FragmentManager
*/
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun addRetainedAfterSaveState() {
@@ -636,6 +698,7 @@
.isNull()
}
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun popBackStackImmediateAfterSaveState() {
@@ -670,6 +733,7 @@
}
}
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun popBackStackAfterSaveState() {
@@ -704,6 +768,7 @@
}
}
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun popBackStackAfterManagerDestroyed() {
@@ -733,6 +798,7 @@
}
}
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun commitWhenFragmentManagerNeverAttached() {
@@ -760,6 +826,7 @@
}
}
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun popBackStackAndFragmentHostDestroyed() {
@@ -796,6 +863,7 @@
}
}
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun commitNowWhenFragmentHostNeverAttached() {
@@ -823,6 +891,7 @@
/**
* When a fragment is saved in non-config, it should be restored to the same index.
*/
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun restoreNonConfig() {
@@ -875,6 +944,7 @@
/**
* Check that retained fragments in the backstack correctly restored after two "configChanges"
*/
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun retainedFragmentInBackstack() {
@@ -1220,6 +1290,7 @@
}
}
+ @Suppress("DEPRECATION")
class OnCreateFragment : Fragment() {
var onCreateCalled: Boolean = false
@@ -1242,6 +1313,7 @@
class RetainedInflatedChildFragment : Fragment(R.layout.nested_inflated_fragment_child) {
internal var mOnInflateCount = 0
+ @Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt
index 93a60cc..867ada4 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt
@@ -340,6 +340,7 @@
fc2.shutdown(viewModelStore)
}
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun testSavedInstanceStateAfterRestore() {
@@ -685,6 +686,7 @@
val retain: Boolean = false
) : StrictFragment() {
+ @Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt
index a3840b2..43c4770 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt
@@ -287,6 +287,7 @@
* Test the availability of getTargetFragment() when the target fragment is
* retained and the referrer fragment is not retained.
*/
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun targetFragmentRetainedNonRetained() {
@@ -323,6 +324,7 @@
* Test the availability of getTargetFragment() when the target fragment is
* not retained and the referrer fragment is retained.
*/
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun targetFragmentNonRetainedRetained() {
@@ -358,6 +360,7 @@
* Test the availability of getTargetFragment() when the target fragment is
* retained and the referrer fragment is also retained.
*/
+ @Suppress("DEPRECATION")
@Test
@UiThreadTest
fun targetFragmentRetainedRetained() {
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt
index 5e24f3d..0cafc8f 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt
@@ -43,6 +43,7 @@
val childFragment: ChildFragment
get() = childFragmentManager.findFragmentByTag(CHILD_FRAGMENT_TAG) as ChildFragment
+ @Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt
index 2c011c6..344db8a 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt
@@ -29,6 +29,7 @@
.commitNowAllowingStateLoss()
}
+ @Suppress("DEPRECATION")
class RetainedFragment : Fragment() {
init {
retainInstance = true
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 0128a8f..7f2dd4a 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -1129,7 +1129,12 @@
* changes, <code>false</code> otherwise.
*
* @see #getRetainInstance()
+ * @deprecated Instead of retaining the Fragment itself, use a non-retained Fragment and keep
+ * retained state in a ViewModel attached to that Fragment. The ViewModel's constructor and
+ * its onCleared() callback provide the signal for initial creation and final destruction of
+ * the retained state.
*/
+ @Deprecated
public void setRetainInstance(boolean retain) {
mRetainInstance = retain;
if (mFragmentManager != null) {
@@ -1149,7 +1154,13 @@
*
* @return whether or not this fragment instance will be retained.
* @see #setRetainInstance(boolean)
+ *
+ * @deprecated Instead of retaining the Fragment itself, use a non-retained Fragment and keep
+ * retained state in a ViewModel attached to that Fragment. The ViewModel's constructor and
+ * its onCleared() callback provide the signal for initial creation and final destruction of
+ * the retained state.
*/
+ @Deprecated
final public boolean getRetainInstance() {
return mRetainInstance;
}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 5e42a1f..0477e84 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -1158,6 +1158,7 @@
return mCurState >= state;
}
+ @SuppressWarnings("deprecation")
void moveToState(@NonNull Fragment f, int newState) {
FragmentStateManager fragmentStateManager = mActive.get(f.mWho);
if (fragmentStateManager == null) {
@@ -1325,7 +1326,7 @@
// fall through
case Fragment.ATTACHED:
if (newState < Fragment.ATTACHED) {
- fragmentStateManager.detach();
+ fragmentStateManager.detach(mNonConfig);
}
}
}
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 beeee96f..f9635d4 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -468,7 +468,7 @@
}
}
- void detach() {
+ void detach(@NonNull FragmentManagerViewModel nonConfig) {
if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(TAG, "movefrom ATTACHED: " + mFragment);
}
@@ -480,7 +480,10 @@
mFragment.mParentFragment = null;
mFragment.mFragmentManager = null;
boolean beingRemoved = mFragment.mRemoving && !mFragment.isInBackStack();
- if (beingRemoved) {
+ if (beingRemoved || nonConfig.shouldDestroy(mFragment)) {
+ if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
+ Log.d(TAG, "initState called for fragment: " + mFragment);
+ }
mFragment.initState();
}
}
diff --git a/gradle.properties b/gradle.properties
index 04c18ae..f3b3e79 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -10,3 +10,5 @@
// Run multiple kotlin compilations in parallel within the same project.
// See also https://github.com/JetBrains/kotlin/blob/1978db9d0e68a2ec29aded30a07e9c3c740c29f6/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt#L100 and https://blog.jetbrains.com/kotlin/2019/01/kotlin-1-3-20-released/
kotlin.parallel.tasks.in.project=true
+# TODO(b/144189353) : remove android.useNewJarCreator once it stops putting illegal timestamps into jars
+android.useNewJarCreator=false
diff --git a/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java b/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
index cd2a421..926311e 100644
--- a/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
+++ b/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
@@ -726,7 +726,7 @@
}
}
VerticalGridView columnView = mColumnViews.get(columnIndex);
- if (hasFocus()) {
+ if (hasFocus() && !columnView.hasFocus()) {
columnView.requestFocus();
}
}
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
index 326272b..210b8aa 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
@@ -160,6 +160,74 @@
.isEqualTo(myArg)
}
+ // Ensure that arguments with multiple characters in the path get matched correctly.
+ @Test
+ fun deepLinkMultiCharacterArgumentMatchWithQueryParams() {
+ val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users/{id}?myarg={myarg}"
+ val deepLink = NavDeepLink(deepLinkArgument)
+
+ val id = 211
+ val myArg = "test"
+ val matchArgs = deepLink.getMatchingArguments(
+ Uri.parse(deepLinkArgument.replace("{id}", id.toString()).replace("{myarg}", myArg)),
+ mapOf("id" to intArgument(),
+ "myarg" to stringArgument())
+ )
+ assertWithMessage("Args should not be null")
+ .that(matchArgs)
+ .isNotNull()
+ assertWithMessage("Args should contain the id")
+ .that(matchArgs?.getInt("id"))
+ .isEqualTo(id)
+ assertWithMessage("Args should contain the argument")
+ .that(matchArgs?.getString("myarg"))
+ .isEqualTo(myArg)
+ }
+
+ // Ensure that a question mark at the end of path params matches same as if there was no
+ // question mark
+ @Test
+ fun deepLinkMultipleArgumentMatchQuestionMarkNoParams() {
+ val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users/{id}?"
+ val deepLink = NavDeepLink(deepLinkArgument)
+
+ val id = 211
+ val matchArgs = deepLink.getMatchingArguments(
+ Uri.parse(deepLinkArgument.replace("{id}", id.toString())),
+ mapOf("id" to intArgument(),
+ "myarg" to stringArgument())
+ )
+ assertWithMessage("Args should not be null")
+ .that(matchArgs)
+ .isNotNull()
+ assertWithMessage("Args should contain the id")
+ .that(matchArgs?.getInt("id"))
+ .isEqualTo(id)
+ }
+
+ // Ensure that path arguments between two literals matches appropriately
+ @Test
+ fun deepLinkMultiCharacterArgumentMiddleMatchWithQueryParams() {
+ val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users/{id}/posts?myarg={myarg}"
+ val deepLink = NavDeepLink(deepLinkArgument)
+
+ val id = 2
+ val myArg = "test"
+ val matchArgs = deepLink.getMatchingArguments(
+ Uri.parse(deepLinkArgument.replace("{id}", id.toString()).replace("{myarg}", myArg)),
+ mapOf("id" to intArgument())
+ )
+ assertWithMessage("Args should not be null")
+ .that(matchArgs)
+ .isNotNull()
+ assertWithMessage("Args should contain the id")
+ .that(matchArgs?.getInt("id"))
+ .isEqualTo(id)
+ assertWithMessage("Args should contain the argument")
+ .that(matchArgs?.getString("myarg"))
+ .isEqualTo(myArg)
+ }
+
@Test
fun deepLinkQueryParamArgumentMatch() {
val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users?id={id}"
@@ -385,7 +453,7 @@
val id = 2
val matchArgs = deepLink.getMatchingArguments(
- Uri.parse("$DEEP_LINK_EXACT_HTTPS/users&extraParam={extraParam}"),
+ Uri.parse("$DEEP_LINK_EXACT_HTTPS/users?extraParam={extraParam}"),
mapOf("id" to intArgument(id))
)
assertWithMessage("Args should not be null")
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java
index af4810b..cbfdd73 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java
@@ -56,7 +56,11 @@
Matcher matcher = Pattern.compile("(\\?)").matcher(uri);
if (matcher.find()) {
buildPathRegex(uri.substring(0, matcher.start()), uriRegex, fillInPattern);
- uriRegex.append("(.+)?");
+ // Match either the end of string if all params are optional or match the
+ // question mark and 0 or more characters after it
+ // We do not use '.*' here because the finalregex would replace it with a quoted
+ // version below.
+ uriRegex.append("($|(\\?(.)*))");
}
mExactDeepLink = false;
for (String paramName : parameterizedUri.getQueryParameterNames()) {
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt
index 36cc993..04e24e3 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt
@@ -22,13 +22,16 @@
import com.google.gson.reflect.TypeToken
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
+import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import org.gradle.api.resources.TextResource
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.incremental.IncrementalTaskInputs
+import org.gradle.work.ChangeType
+import org.gradle.work.Incremental
+import org.gradle.work.InputChanges
import java.io.File
private const val MAPPING_FILE = "file_mappings.json"
@@ -50,8 +53,9 @@
@get:OutputDirectory
lateinit var outputDir: File
+ @get:Incremental
@get:InputFiles
- lateinit var navigationFiles: Provider<List<File>>
+ lateinit var navigationFiles: FileCollection
@get:OutputDirectory
lateinit var incrementalFolder: File
@@ -90,7 +94,7 @@
}
@TaskAction
- internal fun taskAction(inputs: IncrementalTaskInputs) {
+ internal fun taskAction(inputs: InputChanges) {
if (inputs.isIncremental) {
doIncrementalTaskAction(inputs)
} else {
@@ -106,16 +110,21 @@
if (!outputDir.exists() && !outputDir.mkdirs()) {
throw GradleException("Failed to create directory for navigation arguments")
}
- val (mappings, errors) = generateArgs(navigationFiles.get(), outputDir)
+ val (mappings, errors) = generateArgs(navigationFiles.files, outputDir)
writeMappings(mappings)
failIfErrors(errors)
}
- private fun doIncrementalTaskAction(inputs: IncrementalTaskInputs) {
+ private fun doIncrementalTaskAction(inputs: InputChanges) {
val modifiedFiles = mutableSetOf<File>()
val removedFiles = mutableSetOf<File>()
- inputs.outOfDate { change -> modifiedFiles.add(change.file) }
- inputs.removed { change -> removedFiles.add(change.file) }
+ inputs.getFileChanges(navigationFiles).forEach { change ->
+ if (change.changeType == ChangeType.MODIFIED || change.changeType == ChangeType.ADDED) {
+ modifiedFiles.add(change.file)
+ } else if (change.changeType == ChangeType.REMOVED) {
+ removedFiles.add(change.file)
+ }
+ }
val oldMapping = readMappings()
val (newMapping, errors) = generateArgs(modifiedFiles, outputDir)
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt
index 17587b9..e53e45c 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt
@@ -25,6 +25,7 @@
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
+import org.gradle.api.file.FileCollection
import org.gradle.api.provider.ProviderFactory
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
import java.io.File
@@ -70,7 +71,7 @@
) { task ->
setApplicationId(task, variant)
task.rFilePackage = variant.rFilePackage()
- task.navigationFiles = navigationFiles(variant)
+ task.navigationFiles = navigationFiles(variant, project)
task.outputDir = File(project.buildDir, "$GENERATED_PATH/${variant.dirName}")
task.incrementalFolder = File(project.buildDir, "$INCREMENTAL_PATH/${task.name}")
task.useAndroidX = (project.findProperty("android.useAndroidX") == "true").also {
@@ -108,18 +109,21 @@
parsed.getProperty("@package").toString()
}
- private fun navigationFiles(variant: BaseVariant) = providerFactory.provider {
- variant.sourceSets
- .flatMap { it.resDirectories }
- .mapNotNull {
- File(it, "navigation").let { navFolder ->
- if (navFolder.exists() && navFolder.isDirectory) navFolder else null
+ private fun navigationFiles(variant: BaseVariant, project: Project): FileCollection {
+ val fileProvider = providerFactory.provider {
+ variant.sourceSets
+ .flatMap { it.resDirectories }
+ .mapNotNull {
+ File(it, "navigation").let { navFolder ->
+ if (navFolder.exists() && navFolder.isDirectory) navFolder else null
+ }
}
- }
- .flatMap { navFolder -> navFolder.listFiles().asIterable() }
- .filter { file -> file.isFile }
- .groupBy { file -> file.name }
- .map { entry -> entry.value.last() }
+ .flatMap { navFolder -> navFolder.listFiles().asIterable() }
+ .filter { file -> file.isFile }
+ .groupBy { file -> file.name }
+ .map { entry -> entry.value.last() }
+ }
+ return project.files(fileProvider)
}
}
diff --git a/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt b/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt
+++ b/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt
@@ -3,7 +3,7 @@
public abstract class BandPredicate {
ctor public BandPredicate();
- method public abstract boolean canInitiate(android.view.MotionEvent!);
+ method public abstract boolean canInitiate(android.view.MotionEvent);
}
public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
public class Selection<K> implements java.lang.Iterable<K> {
method public boolean contains(K?);
method public boolean isEmpty();
- method public java.util.Iterator<K!>! iterator();
+ method public java.util.Iterator<K!> iterator();
method public int size();
}
public final class SelectionPredicates {
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
}
public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
method public abstract boolean clearSelection();
method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
method public abstract boolean deselect(K);
- method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+ method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
method public abstract boolean hasSelection();
method public abstract boolean isSelected(K?);
method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
public static final class SelectionTracker.Builder<K> {
ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
- method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
}
public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
ctor public StorageStrategy(Class<K!>);
method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
- method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+ method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
}
}
diff --git a/recyclerview/recyclerview-selection/api/current.txt b/recyclerview/recyclerview-selection/api/current.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/current.txt
+++ b/recyclerview/recyclerview-selection/api/current.txt
@@ -3,7 +3,7 @@
public abstract class BandPredicate {
ctor public BandPredicate();
- method public abstract boolean canInitiate(android.view.MotionEvent!);
+ method public abstract boolean canInitiate(android.view.MotionEvent);
}
public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
public class Selection<K> implements java.lang.Iterable<K> {
method public boolean contains(K?);
method public boolean isEmpty();
- method public java.util.Iterator<K!>! iterator();
+ method public java.util.Iterator<K!> iterator();
method public int size();
}
public final class SelectionPredicates {
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
}
public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
method public abstract boolean clearSelection();
method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
method public abstract boolean deselect(K);
- method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+ method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
method public abstract boolean hasSelection();
method public abstract boolean isSelected(K?);
method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
public static final class SelectionTracker.Builder<K> {
ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
- method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
}
public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
ctor public StorageStrategy(Class<K!>);
method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
- method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+ method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
}
}
diff --git a/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt b/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt
+++ b/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt
@@ -3,7 +3,7 @@
public abstract class BandPredicate {
ctor public BandPredicate();
- method public abstract boolean canInitiate(android.view.MotionEvent!);
+ method public abstract boolean canInitiate(android.view.MotionEvent);
}
public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
public class Selection<K> implements java.lang.Iterable<K> {
method public boolean contains(K?);
method public boolean isEmpty();
- method public java.util.Iterator<K!>! iterator();
+ method public java.util.Iterator<K!> iterator();
method public int size();
}
public final class SelectionPredicates {
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
}
public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
method public abstract boolean clearSelection();
method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
method public abstract boolean deselect(K);
- method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+ method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
method public abstract boolean hasSelection();
method public abstract boolean isSelected(K?);
method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
public static final class SelectionTracker.Builder<K> {
ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
- method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
}
public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
ctor public StorageStrategy(Class<K!>);
method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
- method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+ method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
}
}
diff --git a/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt b/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt
+++ b/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt
@@ -3,7 +3,7 @@
public abstract class BandPredicate {
ctor public BandPredicate();
- method public abstract boolean canInitiate(android.view.MotionEvent!);
+ method public abstract boolean canInitiate(android.view.MotionEvent);
}
public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
public class Selection<K> implements java.lang.Iterable<K> {
method public boolean contains(K?);
method public boolean isEmpty();
- method public java.util.Iterator<K!>! iterator();
+ method public java.util.Iterator<K!> iterator();
method public int size();
}
public final class SelectionPredicates {
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
}
public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
method public abstract boolean clearSelection();
method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
method public abstract boolean deselect(K);
- method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+ method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
method public abstract boolean hasSelection();
method public abstract boolean isSelected(K?);
method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
public static final class SelectionTracker.Builder<K> {
ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
- method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
}
public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
ctor public StorageStrategy(Class<K!>);
method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
- method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+ method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
}
}
diff --git a/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt b/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt
index 7058b89..f944138 100644
--- a/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt
+++ b/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt
@@ -3,7 +3,7 @@
public abstract class BandPredicate {
ctor public BandPredicate();
- method public abstract boolean canInitiate(android.view.MotionEvent!);
+ method public abstract boolean canInitiate(android.view.MotionEvent);
}
public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -81,16 +81,17 @@
method public void onChanged();
}
+
public class Selection<K> implements java.lang.Iterable<K> {
method public boolean contains(K?);
method public boolean isEmpty();
- method public java.util.Iterator<K!>! iterator();
+ method public java.util.Iterator<K!> iterator();
method public int size();
}
public final class SelectionPredicates {
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
}
public abstract class SelectionTracker<K> {
@@ -99,7 +100,7 @@
method public abstract boolean clearSelection();
method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
method public abstract boolean deselect(K);
- method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+ method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
method public abstract boolean hasSelection();
method public abstract boolean isSelected(K?);
method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -112,17 +113,17 @@
public static final class SelectionTracker.Builder<K> {
ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
- method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
}
public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -150,9 +151,9 @@
ctor public StorageStrategy(Class<K!>);
method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
- method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+ method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
}
}
diff --git a/recyclerview/recyclerview-selection/api/restricted_current.txt b/recyclerview/recyclerview-selection/api/restricted_current.txt
index 7058b89..f944138 100644
--- a/recyclerview/recyclerview-selection/api/restricted_current.txt
+++ b/recyclerview/recyclerview-selection/api/restricted_current.txt
@@ -3,7 +3,7 @@
public abstract class BandPredicate {
ctor public BandPredicate();
- method public abstract boolean canInitiate(android.view.MotionEvent!);
+ method public abstract boolean canInitiate(android.view.MotionEvent);
}
public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -81,16 +81,17 @@
method public void onChanged();
}
+
public class Selection<K> implements java.lang.Iterable<K> {
method public boolean contains(K?);
method public boolean isEmpty();
- method public java.util.Iterator<K!>! iterator();
+ method public java.util.Iterator<K!> iterator();
method public int size();
}
public final class SelectionPredicates {
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
- method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+ method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
}
public abstract class SelectionTracker<K> {
@@ -99,7 +100,7 @@
method public abstract boolean clearSelection();
method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
method public abstract boolean deselect(K);
- method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+ method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
method public abstract boolean hasSelection();
method public abstract boolean isSelected(K?);
method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -112,17 +113,17 @@
public static final class SelectionTracker.Builder<K> {
ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
- method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
- method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
- method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+ method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+ method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
}
public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -150,9 +151,9 @@
ctor public StorageStrategy(Class<K!>);
method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
- method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
- method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+ method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+ method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
}
}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java
index ca0e11f..bc0cbc98 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java
@@ -16,18 +16,20 @@
package androidx.recyclerview.selection;
-import static androidx.recyclerview.selection.testing.TestEvents.Mouse;
-import static androidx.recyclerview.selection.testing.TestEvents.Touch;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.view.MotionEvent;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.selection.GridModel.GridHost;
import androidx.recyclerview.selection.testing.TestAdapter;
import androidx.recyclerview.selection.testing.TestAutoScroller;
import androidx.recyclerview.selection.testing.TestBandPredicate;
import androidx.recyclerview.selection.testing.TestData;
+import androidx.recyclerview.selection.testing.TestEvents;
import androidx.recyclerview.selection.testing.TestItemKeyProvider;
import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -46,135 +48,148 @@
private List<String> mItems;
private BandSelectionHelper<String> mBandController;
- private boolean mIsActive;
- private TestBandHost mBandHost;
+ private TestHostEnvironment mHostEnv;
private TestBandPredicate mBandPredicate;
private TestAdapter<String> mAdapter;
private SelectionTracker<String> mTracker;
+ TestItemKeyProvider<String> mKeyProvider;
+
+ // Builder for all drag events. Twiddle the button's and other stuff as needed.
+ TestEvents.Builder mBaseEvent;
@Before
public void setup() throws Exception {
mItems = TestData.createStringData(10);
- mIsActive = false;
mAdapter = new TestAdapter<>();
mAdapter.updateTestModelIds(mItems);
- mBandHost = new TestBandHost();
+ mKeyProvider = new TestItemKeyProvider<>(ItemKeyProvider.SCOPE_MAPPED, mAdapter);
+ mHostEnv = new TestHostEnvironment();
mBandPredicate = new TestBandPredicate();
- ItemKeyProvider<String> keyProvider =
- new TestItemKeyProvider<>(ItemKeyProvider.SCOPE_MAPPED, mAdapter);
+
OperationMonitor operationMonitor = new OperationMonitor();
mTracker = new DefaultSelectionTracker<>(
"band-selection-test",
- keyProvider,
+ mKeyProvider,
SelectionPredicates.createSelectAnything(),
StorageStrategy.createStringStorage());
- EventBridge.install(mAdapter, mTracker, keyProvider);
+ EventBridge.install(mAdapter, mTracker, mKeyProvider);
FocusDelegate<String> focusDelegate = FocusDelegate.dummy();
mBandController = new BandSelectionHelper<String>(
- mBandHost,
+ mHostEnv,
new TestAutoScroller(),
- keyProvider,
+ mKeyProvider,
mTracker,
mBandPredicate,
focusDelegate,
- operationMonitor) {
- @Override
- public boolean isActive() {
- return mIsActive;
- }
- };
+ operationMonitor);
+
+ // No buttons pressed. Tests can fiddle with this as needed.
+ mBaseEvent = TestEvents.builder()
+ .location(1, 1)
+ .mouse()
+ .move();
}
- @Test
- public void testReset_HidesBand() {
- mIsActive = true;
- mBandController.reset();
- mBandHost.assertBandHidden();
+ private boolean startBandSelect() {
+ return startBandSelect(mBaseEvent.primary().build());
+ }
+
+ // Allows tests to pass an event that might not start band selection.
+ private boolean startBandSelect(MotionEvent e) {
+ mBandController.onInterceptTouchEvent(null, e);
+ return mBandController.isResetRequired();
+ }
+
+ private boolean stopBandSelect() {
+ mBandController.onInterceptTouchEvent(null, mBaseEvent.up().build());
+ return !mBandController.isResetRequired();
}
@Test
public void testStart() {
- assertTrue(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
+ assertTrue(startBandSelect());
}
@Test
- public void testStart_NoItems() {
+ public void testStart_RejectedByPredicate() {
+ mBandPredicate.setCanInitiate(false);
+ assertFalse(startBandSelect());
+ }
+
+ @Test
+ public void testRequiresReset() {
+ assertFalse(mBandController.isResetRequired());
+ startBandSelect();
+ assertTrue(mBandController.isResetRequired());
+ }
+
+ @Test
+ public void testReset() {
+ startBandSelect();
+ mBandController.reset();
+ assertFalse(mBandController.isResetRequired());
+ }
+
+ @Test
+ public void testReset_HidesBand() {
+ startBandSelect();
+ mBandController.reset();
+ mHostEnv.assertBandHidden();
+ }
+
+ @Test
+ public void testStart_IgnoresNonPrimaryDragEvents() {
+ // W/ no buttons pressed.
+ assertFalse(startBandSelect(mBaseEvent.build()));
+
+ // With wrong buttons pressed.
+ assertFalse(startBandSelect(mBaseEvent.secondary().build()));
+ assertFalse(startBandSelect(mBaseEvent.tertiary().build()));
+ }
+
+ @Test
+ public void testStart_IgnoresNonMoveEvents() {
+ // Primary button has to be pressed for controller to pay attention to an event.
+ mBaseEvent.primary();
+
+ // Override MOVE action with UP and DOWN to verify they are ignored.
+ assertFalse(startBandSelect(mBaseEvent.up().build()));
+ assertFalse(startBandSelect(mBaseEvent.down().build()));
+ }
+
+ @Test
+ public void testStarts_NoItems() {
// Band selection can happen in a view without any items.
mAdapter.updateTestModelIds(Collections.<String>emptyList());
- assertTrue(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
- }
- @Test
- public void testNoStart_NoButtons() {
- assertFalse(mBandController.shouldStart(Mouse.MOVE));
- }
-
- @Test
- public void testNoStart_SecondaryButton() {
- assertFalse(mBandController.shouldStart(Mouse.SECONDARY_DRAG));
- }
-
- @Test
- public void testNoStart_TertiaryButton() {
- assertFalse(mBandController.shouldStart(Mouse.TERTIARY_DRAG));
- }
-
- @Test
- public void testNoStart_Touch() {
- assertFalse(mBandController.shouldStart(Touch.MOVE));
- }
-
- @Test
- public void testNoStart_RejectedByPredicate() {
- mBandPredicate.setCanInitiate(false);
- assertFalse(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
- }
-
- @Test
- public void testNoStart() {
- // only starts on
- assertFalse(mBandController.shouldStart(Mouse.DOWN));
- assertFalse(mBandController.shouldStart(Mouse.UP));
- assertFalse(mBandController.shouldStart(Mouse.POINTER_UP));
- assertFalse(mBandController.shouldStart(Mouse.POINTER_DOWN));
- }
-
-
- @Test
- public void testNoStart_AlreadyStarted() {
- mIsActive = true;
- assertFalse(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
+ assertTrue(startBandSelect());
}
@Test
public void testStops() {
- mIsActive = true;
- assertTrue(mBandController.shouldStop(Mouse.UP));
+ startBandSelect();
+ assertTrue(stopBandSelect());
}
@Test
- public void testNoStop_Down() {
- mIsActive = true;
- // Not really sure when this would, happen, maybe a secondary
- // or tertiary button press while dragging?
- assertFalse(mBandController.shouldStop(Touch.DOWN)); // :) Touch Down!
+ public void testStop_IgnoresUpWhenNotStarted() {
+ assertTrue(stopBandSelect());
}
- @Test
- public void testNoStop_NotActive() {
- assertFalse(mBandController.shouldStop(Mouse.UP));
- assertFalse(mBandController.shouldStop(Touch.MOVE));
- }
+ // GridHost extends BandHost. We satisfy both by implementing GridHost.
+ private final class TestHostEnvironment extends GridHost<String> {
- private final class TestBandHost extends BandSelectionHelper.BandHost<String> {
private boolean mBandHidden;
@Override
GridModel<String> createGridModel() {
- throw new UnsupportedOperationException();
+ return new GridModel<String>(
+ this,
+ mKeyProvider,
+ SelectionPredicates.createSelectAnything());
}
@Override
@@ -194,6 +209,42 @@
@Override
void addOnScrollListener(OnScrollListener listener) {
+ // ignored for testing
+ }
+
+ @Override
+ void removeOnScrollListener(@NonNull OnScrollListener listener) {
+ // ignored for testing
+ }
+
+ @Override
+ Point createAbsolutePoint(@NonNull Point relativePoint) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ Rect getAbsoluteRectForChildViewAt(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ int getAdapterPositionAt(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ int getColumnCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ int getVisibleChildCount() {
+ return 0;
+ }
+
+ @Override
+ boolean hasView(int adapterPosition) {
+ throw new UnsupportedOperationException();
}
}
}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
index 5a0e600..8a81ec7 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
@@ -24,6 +24,7 @@
import android.os.Bundle;
import android.util.SparseBooleanArray;
+import androidx.annotation.NonNull;
import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
import androidx.recyclerview.selection.testing.Bundles;
import androidx.recyclerview.selection.testing.SelectionProbe;
@@ -68,7 +69,7 @@
mSelectionPredicate = new SelectionPredicate<String>() {
@Override
- public boolean canSetStateForKey(String id, boolean nextState) {
+ public boolean canSetStateForKey(@NonNull String id, boolean nextState) {
return !nextState || !mIgnored.contains(id);
}
@@ -219,6 +220,70 @@
}
@Test
+ public void testRequiresReset_ForSelection() {
+ mTracker.select(mItems.get(1));
+
+ assertTrue(mTracker.isResetRequired());
+ }
+
+ @Test
+ public void testRequiresReset_ForProvisionalSelection() {
+ Set<String> items = new HashSet<>();
+ items.add(mItems.get(1));
+
+ mTracker.setProvisionalSelection(items);
+
+ assertTrue(mTracker.isResetRequired());
+ }
+
+ @Test
+ public void testRequiresReset_ForEstablishedRange() {
+ mTracker.startRange(15);
+
+ assertTrue(mTracker.isResetRequired());
+ }
+
+ @Test
+ public void testReset_ForSelection() {
+ mTracker.select(mItems.get(1));
+
+ mTracker.reset();
+ assertFalse(mTracker.isResetRequired());
+ }
+
+ @Test
+ public void testReset_ForProvisionalSelection() {
+ Set<String> items = new HashSet<>();
+ items.add(mItems.get(1));
+ mTracker.setProvisionalSelection(items);
+
+ mTracker.reset();
+ assertFalse(mTracker.isResetRequired());
+ }
+
+ @Test
+ public void testReset_Combined() {
+ mTracker.select(mItems.get(1));
+
+ Set<String> items = new HashSet<>();
+ items.add(mItems.get(1));
+ mTracker.setProvisionalSelection(items);
+
+ mTracker.startRange(15);
+
+ mTracker.reset();
+ assertFalse(mTracker.isResetRequired());
+ }
+
+ @Test
+ public void testReset_ForEstablishedRange() {
+ mTracker.startRange(15);
+
+ mTracker.reset();
+ assertFalse(mTracker.isResetRequired());
+ }
+
+ @Test
public void testRangeSelection() {
mTracker.startRange(15);
mTracker.extendRange(19);
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
index 11db0a1..f3944cf 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
@@ -78,6 +78,19 @@
}
@Test
+ public void testRequiresReset() {
+ mHelper.start();
+ assertTrue(mHelper.isResetRequired());
+ }
+
+ @Test
+ public void testReset() {
+ mHelper.start();
+ mHelper.reset();
+ assertFalse(mHelper.isResetRequired());
+ }
+
+ @Test
public void testResetsOnCancel() {
assertFalse(mHelper.onInterceptTouchEvent(null, MOVE));
}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java
index a6568f9..a25a5d1 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java
@@ -75,6 +75,19 @@
mListener.assertLastState(false);
}
+ @Test
+ public void testRequiresReset() {
+ mMonitor.start();
+ assertTrue(mMonitor.asResettable().isResetRequired());
+ }
+
+ @Test
+ public void testReset() {
+ mMonitor.start();
+ mMonitor.asResettable().reset();
+ assertFalse(mMonitor.asResettable().isResetRequired());
+ }
+
private static final class TestListener implements OperationMonitor.OnChangeListener {
private boolean mLastState;
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java
index 704c8aa..8ff3c2b 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java
@@ -18,7 +18,7 @@
import androidx.recyclerview.selection.testing.TestData;
import androidx.recyclerview.selection.testing.TestEvents;
-import androidx.recyclerview.selection.testing.TestRunnable;
+import androidx.recyclerview.selection.testing.TestResettable;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -39,51 +39,74 @@
private static final List<String> ITEMS = TestData.createStringData(100);
private ResetManager<String> mManager;
- private TestRunnable mListern1;
- private TestRunnable mListern2;
+ private TestResettable mResettable1;
+ private TestResettable mResettable2;
@Before
public void setUp() {
mManager = new ResetManager();
- mListern1 = new TestRunnable();
- mListern2 = new TestRunnable();
- mManager.addResetListener(mListern1);
- mManager.addResetListener(mListern2);
+ mResettable1 = new TestResettable(true);
+ mResettable2 = new TestResettable(true);
+ mManager.addResetHandler(mResettable1);
+ mManager.addResetHandler(mResettable2);
}
@Test
public void notifiesListenersOnCancelEvent() {
mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Unknown.CANCEL);
- mListern1.assertRun();
- mListern2.assertRun();
+ mResettable1.assertReset();
+ mResettable2.assertReset();
+ }
+
+ @Test
+ public void notifiesListenersOnSelectionCleared() {
+ mManager.getSelectionObserver().onSelectionCleared();
+ mResettable1.assertReset();
+ mResettable2.assertReset();
+ }
+
+ @Test
+ public void notifiesListenersOnSelectionRefreshed() {
+ mManager.getSelectionObserver().onSelectionRefresh();
+ mResettable1.assertReset();
+ mResettable2.assertReset();
+ }
+
+ @Test
+ public void notifiesListenersOnSelectionRestored() {
+ mManager.getSelectionObserver().onSelectionRestored();
+ mResettable1.assertReset();
+ mResettable2.assertReset();
}
@Test
public void ignoresNonCancelEvents() {
mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Mouse.CLICK);
mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Touch.TAP);
- mListern1.assertNotRun();
- mListern2.assertNotRun();
+ mResettable1.assertNotReset();
+ mResettable2.assertNotReset();
}
+
@Test
- public void notifiesListenersOnSelectionCleared() {
+ public void ignoresWhenResetNotRequired() {
+ mResettable1.setResetRequired(false);
+ mResettable2.setResetRequired(false);
+
+ mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Unknown.CANCEL);
+ mResettable1.assertNotReset();
+ mResettable2.assertNotReset();
+
mManager.getSelectionObserver().onSelectionCleared();
- mListern1.assertRun();
- mListern2.assertRun();
- }
+ mResettable1.assertNotReset();
+ mResettable2.assertNotReset();
- @Test
- public void notifiesListenersOnSelectionRefreshed() {
mManager.getSelectionObserver().onSelectionRefresh();
- mListern1.assertRun();
- mListern2.assertRun();
- }
+ mResettable1.assertNotReset();
+ mResettable2.assertNotReset();
- @Test
- public void notifiesListenersOnSelectionRestored() {
mManager.getSelectionObserver().onSelectionRestored();
- mListern1.assertRun();
- mListern2.assertRun();
+ mResettable1.assertNotReset();
+ mResettable2.assertNotReset();
}
}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java
index ca21b9c..a03bd28 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java
@@ -18,6 +18,7 @@
import android.view.MotionEvent;
+import androidx.annotation.NonNull;
import androidx.recyclerview.selection.BandPredicate;
public class TestBandPredicate extends BandPredicate {
@@ -29,7 +30,7 @@
}
@Override
- public boolean canInitiate(MotionEvent e) {
+ public boolean canInitiate(@NonNull MotionEvent e) {
return mCanInitiate;
}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java
index 88c1ca9..44dbe1b 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java
@@ -18,6 +18,7 @@
import android.view.MotionEvent;
+import androidx.annotation.NonNull;
import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
import androidx.recyclerview.widget.RecyclerView;
@@ -55,7 +56,7 @@
}
@Override
- public boolean inDragRegion(MotionEvent event) {
+ public boolean inDragRegion(@NonNull MotionEvent event) {
return mInDragRegion;
}
@@ -90,7 +91,7 @@
}
@Override
- public boolean inSelectionHotspot(MotionEvent e) {
+ public boolean inSelectionHotspot(@NonNull MotionEvent e) {
return mInSelectionHotspot;
}
}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java
index 82c2119..33294d9 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java
@@ -18,6 +18,7 @@
import android.view.MotionEvent;
+import androidx.annotation.NonNull;
import androidx.recyclerview.selection.ItemDetailsLookup;
import javax.annotation.Nullable;
@@ -30,7 +31,7 @@
private @Nullable TestItemDetails mItem;
@Override
- public @Nullable ItemDetails<String> getItemDetails(MotionEvent e) {
+ public @Nullable ItemDetails<String> getItemDetails(@NonNull MotionEvent e) {
return mItem;
}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestResettable.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestResettable.java
new file mode 100644
index 0000000..09a3e28
--- /dev/null
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestResettable.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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.recyclerview.selection.testing;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.recyclerview.selection.Resettable;
+
+public final class TestResettable implements Resettable {
+
+ private boolean mResetRequired;
+ private boolean mWasReset;
+
+ public TestResettable() {
+ // mRequiresReset defaults to false.
+ }
+
+ public TestResettable(boolean requiresReset) {
+ mResetRequired = requiresReset;
+ }
+
+ @Override
+ public void reset() {
+ mWasReset = true;
+ }
+
+ public void setResetRequired(boolean required) {
+ mResetRequired = required;
+ }
+
+ @Override
+ public boolean isResetRequired() {
+ return mResetRequired;
+ }
+
+ public void assertReset() {
+ assertTrue(mWasReset);
+ }
+
+ public void assertNotReset() {
+ assertFalse(mWasReset);
+ }
+}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java
index fbe06fe..49fba73 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import androidx.annotation.NonNull;
import androidx.recyclerview.selection.SelectionTracker.SelectionObserver;
import java.util.HashSet;
@@ -51,7 +52,7 @@
}
@Override
- public void onItemStateChanged(K key, boolean selected) {
+ public void onItemStateChanged(@NonNull K key, boolean selected) {
if (selected) {
if (mStrict) {
assertNotSelected(key);
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java
index 32f16ee..de284b5 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java
@@ -16,6 +16,7 @@
package androidx.recyclerview.selection.testing;
+import androidx.annotation.NonNull;
import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
public final class TestSelectionPredicate<K> extends SelectionPredicate<K> {
@@ -37,7 +38,7 @@
}
@Override
- public boolean canSetStateForKey(K key, boolean nextState) {
+ public boolean canSetStateForKey(@NonNull K key, boolean nextState) {
return mValue;
}
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java
index 5be26dd..3ec4ccb 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java
@@ -40,7 +40,7 @@
/**
* @return true if band selection can be initiated in response to the {@link MotionEvent}.
*/
- public abstract boolean canInitiate(MotionEvent e);
+ public abstract boolean canInitiate(@NonNull MotionEvent e);
@SuppressWarnings("WeakerAccess") /* synthetic access */
static boolean hasSupportedLayoutManager(@NonNull RecyclerView recyclerView) {
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java
index 5e70fd6..591d127 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java
@@ -28,7 +28,6 @@
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
@@ -50,7 +49,7 @@
*
* @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
*/
-class BandSelectionHelper<K> implements OnItemTouchListener {
+class BandSelectionHelper<K> implements OnItemTouchListener, Resettable {
static final String TAG = "BandSelectionHelper";
static final boolean DEBUG = false;
@@ -140,18 +139,18 @@
lock);
}
- @VisibleForTesting
- boolean isActive() {
- boolean active = mModel != null;
- if (DEBUG) mLock.checkStarted(active);
- return active;
+ private boolean isActive() {
+ boolean started = mModel != null;
+ if (DEBUG) mLock.checkStarted(started);
+ return started;
}
/**
* Clients must call reset when there are any material changes to the layout of items
* in RecyclerView.
*/
- void reset() {
+ @Override
+ public void reset() {
if (!isActive()) {
if (DEBUG) Log.d(TAG, "Ignoring reset request, not active.");
return;
@@ -170,8 +169,12 @@
// mLock is reset by reset manager.
}
- @VisibleForTesting
- boolean shouldStart(@NonNull MotionEvent e) {
+ @Override
+ public boolean isResetRequired() {
+ return isActive();
+ }
+
+ private boolean shouldStart(@NonNull MotionEvent e) {
// b/30146357 && b/23793622. onInterceptTouchEvent does not dispatch events to onTouchEvent
// unless the event is != ACTION_DOWN. Thus, we need to actually start band selection when
// mouse moves.
@@ -181,8 +184,7 @@
&& !isActive();
}
- @VisibleForTesting
- boolean shouldStop(@NonNull MotionEvent e) {
+ private boolean shouldStop(@NonNull MotionEvent e) {
return isActive() && MotionEvents.isActionUp(e);
}
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
index 85d695b..61985cf 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
@@ -50,7 +50,7 @@
*/
@RestrictTo(LIBRARY)
@SuppressWarnings("unchecked")
-public class DefaultSelectionTracker<K> extends SelectionTracker<K> {
+public class DefaultSelectionTracker<K> extends SelectionTracker<K> implements Resettable {
private static final String TAG = "DefaultSelectionTracker";
private static final String EXTRA_SELECTION_PREFIX = "androidx.recyclerview.selection";
@@ -106,13 +106,16 @@
mObservers.add(callback);
}
+ /**
+ * @return true if there is a primary or previsional selection.
+ */
@Override
public boolean hasSelection() {
return !mSelection.isEmpty();
}
@Override
- public Selection<K> getSelection() {
+ public @NonNull Selection<K> getSelection() {
return mSelection;
}
@@ -157,8 +160,6 @@
@Override
public boolean clearSelection() {
- // Short circuiting guards against infinite recurision during reset.
- // See companion test for some supporting details.
if (!hasSelection()) {
if (DEBUG) Log.d(TAG, "Ignoring clearSelection request. No selection.");
return false;
@@ -199,13 +200,19 @@
return prevSelection;
}
- void reset() {
+ @Override
+ public void reset() {
if (DEBUG) Log.d(TAG, "Received reset request.");
clearSelection();
mRange = null;
}
@Override
+ public boolean isResetRequired() {
+ return hasSelection() || isRangeActive();
+ }
+
+ @Override
public boolean select(@NonNull K key) {
checkArgument(key != null);
@@ -377,7 +384,7 @@
}
@Override
- protected AdapterDataObserver getAdapterDataObserver() {
+ protected @NonNull AdapterDataObserver getAdapterDataObserver() {
return mAdapterObserver;
}
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
index 763d789..046a8af 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
@@ -37,7 +37,7 @@
* when used in conjunction with RecyclerView and other classes in the ReyclerView
* selection support package.
*/
-final class GestureSelectionHelper implements OnItemTouchListener {
+final class GestureSelectionHelper implements OnItemTouchListener, Resettable {
private static final String TAG = "GestureSelectionHelper";
@@ -162,12 +162,18 @@
/**
* Immediately "Stops" active gesture selection, and resets all related state.
*/
+ @Override
public void reset() {
if (DEBUG) Log.d(TAG, "Received reset request.");
mStarted = false;
mScroller.reset();
}
+ @Override
+ public boolean isResetRequired() {
+ return mStarted;
+ }
+
private void endSelection() {
mStarted = false;
mScroller.reset();
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
index e2ac2e1..1cdf135 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
@@ -44,7 +44,7 @@
* mRecyclerView = recyclerView;
* }
*
- * public ItemDetails<Uri> getItemDetails(MotionEvent e) {
+ * public @Nullable ItemDetails<Uri> getItemDetails(@NonNull MotionEvent e) {
* View view = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
* if (view != null) {
* ViewHolder holder = mRecyclerView.getChildViewHolder(view);
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java
index d074df5..53d4b82 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java
@@ -16,6 +16,7 @@
package androidx.recyclerview.selection;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.core.util.Preconditions.checkArgument;
import static androidx.core.util.Preconditions.checkState;
import static androidx.recyclerview.selection.Shared.DEBUG;
@@ -24,6 +25,7 @@
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
import java.util.ArrayList;
import java.util.List;
@@ -45,8 +47,26 @@
private static final String TAG = "OperationMonitor";
+ private final List<OnChangeListener> mListeners = new ArrayList<>();
+
+ // Ideally OperationMonitor would implement Resettable
+ // directly, but Metalava couldn't understand that
+ // `OperationMonitor` was public API while `Resettable` was
+ // not. This is our klunkuy workaround.
+ private final Resettable mResettable = new Resettable() {
+
+ @Override
+ public boolean isResetRequired() {
+ return OperationMonitor.this.isResetRequired();
+ }
+
+ @Override
+ public void reset() {
+ OperationMonitor.this.reset();
+ }
+ };
+
private int mNumOps = 0;
- private List<OnChangeListener> mListeners = new ArrayList<>();
@MainThread
synchronized void start() {
@@ -74,6 +94,8 @@
}
}
+ /** @hide */
+ @RestrictTo(LIBRARY)
@MainThread
synchronized void reset() {
if (DEBUG) Log.d(TAG, "Received reset request.");
@@ -84,10 +106,15 @@
notifyStateChanged();
}
+ /** @hide */
+ @RestrictTo(LIBRARY)
+ synchronized boolean isResetRequired() {
+ return isStarted();
+ }
+
/**
* @return true if there are any running operations.
*/
- @SuppressWarnings("unused")
public synchronized boolean isStarted() {
return mNumOps > 0;
}
@@ -126,6 +153,15 @@
}
/**
+ * Work around b/139109223.
+ * @hide
+ */
+ @RestrictTo(LIBRARY)
+ @NonNull Resettable asResettable() {
+ return mResettable;
+ }
+
+ /**
* Listen to changes in operation status. Authors should avoid
* changing the Adapter model while there are active operations.
*/
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java
index 61a91b3..009db1b 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java
@@ -30,11 +30,9 @@
import java.util.List;
/**
- * Manager resetting various states across the lib.
- *
- * E.g....
- * When selection is explicitly cleared, reset.
- * When cancel event is received, reset.
+ * Class managing resetting of library state in response to specific
+ * events like clearing of selection and MotionEvent.ACTION_CANCEL
+ * events.
*
* @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
*/
@@ -42,7 +40,7 @@
private static final String TAG = "ResetManager";
- private final List<Runnable> mListeners = new ArrayList<>();
+ private final List<Resettable> mResetHandlers = new ArrayList<>();
private final OnItemTouchListener mInputListener = new OnItemTouchListener() {
@Override
@@ -50,7 +48,7 @@
@NonNull MotionEvent e) {
if (MotionEvents.isActionCancel(e)) {
if (DEBUG) Log.d(TAG, "Received CANCEL event.");
- notifyResetListeners();
+ callResetHandlers();
}
return false;
}
@@ -64,23 +62,29 @@
}
};
+ // Resettable interface has a #requiresReset method because DefaultSelectionTracker
+ // (owner of the state we observer with our SelectionObserver) is, itself,
+ // a Resettable. Such an arrangement introduces the real possibility of infinite recursion.
+ // When we call reset on DefaultSelectionTracker it'll eventually call back to
+ // notify us of the change via onSelectionCleared. We avoid recursion by
+ // checking #requiresReset before calling reset again.
private final SelectionObserver<K> mSelectionObserver = new SelectionObserver<K>() {
@Override
protected void onSelectionCleared() {
if (DEBUG) Log.d(TAG, "Received onSelectionCleared event.");
- notifyResetListeners();
+ callResetHandlers();
}
@Override
public void onSelectionRefresh() {
if (DEBUG) Log.d(TAG, "Received onSelectionRefresh event.");
- notifyResetListeners();
+ callResetHandlers();
}
@Override
public void onSelectionRestored() {
if (DEBUG) Log.d(TAG, "Received onSelectionRestored event.");
- notifyResetListeners();
+ callResetHandlers();
}
};
@@ -93,19 +97,17 @@
}
/**
- * Registers a new listener.
+ * Registers a new Resettable.
*/
- void addResetListener(@NonNull Runnable listener) {
- mListeners.add(listener);
+ void addResetHandler(@NonNull Resettable handler) {
+ mResetHandlers.add(handler);
}
- public void forceReset() {
- notifyResetListeners();
- }
-
- void notifyResetListeners() {
- for (Runnable listener : mListeners) {
- listener.run();
+ void callResetHandlers() {
+ for (Resettable handler : mResetHandlers) {
+ if (handler.isResetRequired()) {
+ handler.reset();
+ }
}
}
}
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Resettable.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Resettable.java
new file mode 100644
index 0000000..85092aa
--- /dev/null
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Resettable.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.recyclerview.selection;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+
+import androidx.annotation.RestrictTo;
+
+/**
+ * Represents an object that can be reset and can advise on it's
+ * need to be reset.
+ *
+ * <p>Calling {@link #isResetRequired()} on an instance of {@link Resettable}
+ * should always return false when called immediately after {@link #reset()}
+ * has been called.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public interface Resettable {
+
+ /**
+ * @return true if the object requires reset.
+ */
+ boolean isResetRequired();
+
+ /**
+ * Resets the object state.
+ */
+ void reset();
+}
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java
index 6c49015..11dc284 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java
@@ -90,7 +90,7 @@
* {@inheritDoc}
*/
@Override
- public Iterator<K> iterator() {
+ public @NonNull Iterator<K> iterator() {
return mSelection.iterator();
}
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java
index 1e13bde..58780af 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java
@@ -34,7 +34,7 @@
* @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
* @return
*/
- public static <K> SelectionPredicate<K> createSelectAnything() {
+ public static @NonNull <K> SelectionPredicate<K> createSelectAnything() {
return new SelectionPredicate<K>() {
@Override
public boolean canSetStateForKey(@NonNull K key, boolean nextState) {
@@ -60,7 +60,7 @@
* @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
* @return
*/
- public static <K> SelectionPredicate<K> createSelectSingleAnything() {
+ public static @NonNull <K> SelectionPredicate<K> createSelectSingleAnything() {
return new SelectionPredicate<K>() {
@Override
public boolean canSetStateForKey(@NonNull K key, boolean nextState) {
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
index e340f3c..50cc4ceb 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
@@ -126,7 +126,7 @@
* of the selection that will not reflect future changes
* to selection.
*/
- public abstract Selection<K> getSelection();
+ public abstract @NonNull Selection<K> getSelection();
/**
* Updates {@code dest} to reflect the current selection.
@@ -183,7 +183,7 @@
/** @hide */
@RestrictTo(LIBRARY)
- protected abstract AdapterDataObserver getAdapterDataObserver();
+ protected abstract @NonNull AdapterDataObserver getAdapterDataObserver();
/**
* Attempts to establish a range selection at {@code position}, selecting the item
@@ -560,7 +560,7 @@
* @param predicate the predicate to be used.
* @return this
*/
- public Builder<K> withSelectionPredicate(
+ public @NonNull Builder<K> withSelectionPredicate(
@NonNull SelectionPredicate<K> predicate) {
checkArgument(predicate != null);
@@ -575,7 +575,7 @@
* @param monitor the monitor to be used
* @return this
*/
- public Builder<K> withOperationMonitor(
+ public @NonNull Builder<K> withOperationMonitor(
@NonNull OperationMonitor monitor) {
checkArgument(monitor != null);
@@ -589,7 +589,7 @@
* @param delegate the delegate to be used
* @return this
*/
- public Builder<K> withFocusDelegate(@NonNull FocusDelegate<K> delegate) {
+ public @NonNull Builder<K> withFocusDelegate(@NonNull FocusDelegate<K> delegate) {
checkArgument(delegate != null);
mFocusDelegate = delegate;
return this;
@@ -601,7 +601,7 @@
* @param listener the listener to be used
* @return this
*/
- public Builder<K> withOnItemActivatedListener(
+ public @NonNull Builder<K> withOnItemActivatedListener(
@NonNull OnItemActivatedListener<K> listener) {
checkArgument(listener != null);
@@ -616,7 +616,7 @@
* @param listener the listener to be used
* @return this
*/
- public Builder<K> withOnContextClickListener(
+ public @NonNull Builder<K> withOnContextClickListener(
@NonNull OnContextClickListener listener) {
checkArgument(listener != null);
@@ -631,7 +631,7 @@
* @param listener the listener to be used
* @return this
*/
- public Builder<K> withOnDragInitiatedListener(
+ public @NonNull Builder<K> withOnDragInitiatedListener(
@NonNull OnDragInitiatedListener listener) {
checkArgument(listener != null);
@@ -651,7 +651,7 @@
* and only that tool type. This method will be removed in a future release.
*/
@Deprecated
- public Builder<K> withGestureTooltypes(int... toolTypes) {
+ public @NonNull Builder<K> withGestureTooltypes(@NonNull int... toolTypes) {
Log.w(TAG, "Setting gestureTooltypes is likely to result in unexpected behavior.");
mGestureToolTypes = toolTypes;
return this;
@@ -662,7 +662,7 @@
*
* @return this
*/
- public Builder<K> withBandOverlay(@DrawableRes int bandOverlayId) {
+ public @NonNull Builder<K> withBandOverlay(@DrawableRes int bandOverlayId) {
mBandOverlayId = bandOverlayId;
return this;
}
@@ -672,7 +672,7 @@
*
* @return this
*/
- public Builder<K> withBandPredicate(@NonNull BandPredicate bandPredicate) {
+ public @NonNull Builder<K> withBandPredicate(@NonNull BandPredicate bandPredicate) {
mBandPredicate = bandPredicate;
return this;
}
@@ -690,7 +690,7 @@
* and only that tool type. This method will be removed in a future release.
*/
@Deprecated
- public Builder<K> withPointerTooltypes(int... toolTypes) {
+ public @NonNull Builder<K> withPointerTooltypes(@NonNull int... toolTypes) {
Log.w(TAG, "Setting pointerTooltypes is likely to result in unexpected behavior.");
mPointerToolTypes = toolTypes;
return this;
@@ -701,7 +701,7 @@
*
* @return this
*/
- public SelectionTracker<K> build() {
+ public @NonNull SelectionTracker<K> build() {
DefaultSelectionTracker<K> tracker = new DefaultSelectionTracker<>(
mSelectionId, mKeyProvider, mSelectionPredicate, mStorage);
@@ -761,9 +761,9 @@
// stream, not even ACTION_CANCEL events.
eventRouter.set(MotionEvent.TOOL_TYPE_UNKNOWN, resetMgr.getInputListener());
- resetMgr.addResetListener(tracker::reset);
- resetMgr.addResetListener(mMonitor::reset);
- resetMgr.addResetListener(gestureHelper::reset);
+ resetMgr.addResetHandler(tracker);
+ resetMgr.addResetHandler(mMonitor.asResettable());
+ resetMgr.addResetHandler(gestureHelper);
// But before you move on, there's more work to do. Event plumbing has been
// installed, but we haven't registered any of our helpers or callbacks.
@@ -870,7 +870,7 @@
mFocusDelegate,
mMonitor);
- resetMgr.addResetListener(bandHelper::reset);
+ resetMgr.addResetHandler(bandHelper);
}
OnItemTouchListener pointerEventHandler = new PointerDragEventInterceptor(
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java
index 9334d8a..1fb7b75 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java
@@ -39,11 +39,11 @@
* for more detailed advice on which key type to use for your selection keys.
*
* @param <K> Selection key type. Built in support is provided for String, Long, and Parcelable
- * types. Use the respective factory method to create a StorageStrategy instance
- * appropriate to the desired type.
- * {@link #createStringStorage()},
- * {@link #createParcelableStorage(Class)},
- * {@link #createLongStorage()}
+ * types. Use the respective factory method to create a StorageStrategy instance
+ * appropriate to the desired type.
+ * {@link #createStringStorage()},
+ * {@link #createParcelableStorage(Class)},
+ * {@link #createLongStorage()}
*/
public abstract class StorageStrategy<K> {
@@ -69,7 +69,6 @@
* Create a {@link Selection} from supplied {@link Bundle}.
*
* @param state Bundle instance that may contain parceled Selection instance.
- * @return
*/
public abstract @Nullable Selection<K> asSelection(@NonNull Bundle state);
@@ -77,7 +76,6 @@
* Creates a {@link Bundle} from supplied {@link Selection}.
*
* @param selection The selection to asBundle.
- * @return
*/
public abstract @NonNull Bundle asBundle(@NonNull Selection<K> selection);
@@ -89,21 +87,22 @@
* @return StorageStrategy suitable for use with {@link Parcelable} keys
* (like {@link android.net.Uri}).
*/
- public static <K extends Parcelable> StorageStrategy<K> createParcelableStorage(Class<K> type) {
+ public static @NonNull <K extends Parcelable> StorageStrategy<K> createParcelableStorage(
+ @NonNull Class<K> type) {
return new ParcelableStorageStrategy<>(type);
}
/**
* @return StorageStrategy suitable for use with {@link String} keys.
*/
- public static StorageStrategy<String> createStringStorage() {
+ public static @NonNull StorageStrategy<String> createStringStorage() {
return new StringStorageStrategy();
}
/**
* @return StorageStrategy suitable for use with {@link Long} keys.
*/
- public static StorageStrategy<Long> createLongStorage() {
+ public static @NonNull StorageStrategy<Long> createLongStorage() {
return new LongStorageStrategy();
}
@@ -191,7 +190,7 @@
private static class ParcelableStorageStrategy<K extends Parcelable>
extends StorageStrategy<K> {
- ParcelableStorageStrategy(Class<K> type) {
+ ParcelableStorageStrategy(@NonNull Class<K> type) {
super(type);
checkArgument(Parcelable.class.isAssignableFrom(type));
}
diff --git a/room/common/api/2.3.0-alpha01.txt b/room/common/api/2.3.0-alpha01.txt
index 238967d..4e032bd 100644
--- a/room/common/api/2.3.0-alpha01.txt
+++ b/room/common/api/2.3.0-alpha01.txt
@@ -167,6 +167,8 @@
field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+ field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+ field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/current.txt b/room/common/api/current.txt
index 238967d..4e032bd 100644
--- a/room/common/api/current.txt
+++ b/room/common/api/current.txt
@@ -167,6 +167,8 @@
field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+ field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+ field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/public_plus_experimental_2.3.0-alpha01.txt b/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
index 238967d..4e032bd 100644
--- a/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
+++ b/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
@@ -167,6 +167,8 @@
field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+ field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+ field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/public_plus_experimental_current.txt b/room/common/api/public_plus_experimental_current.txt
index 238967d..4e032bd 100644
--- a/room/common/api/public_plus_experimental_current.txt
+++ b/room/common/api/public_plus_experimental_current.txt
@@ -167,6 +167,8 @@
field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+ field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+ field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/restricted_2.3.0-alpha01.txt b/room/common/api/restricted_2.3.0-alpha01.txt
index ed6c4ee..a2a0510 100644
--- a/room/common/api/restricted_2.3.0-alpha01.txt
+++ b/room/common/api/restricted_2.3.0-alpha01.txt
@@ -176,6 +176,8 @@
field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+ field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+ field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/restricted_current.txt b/room/common/api/restricted_current.txt
index ed6c4ee..a2a0510 100644
--- a/room/common/api/restricted_current.txt
+++ b/room/common/api/restricted_current.txt
@@ -176,6 +176,8 @@
field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+ field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+ field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/src/main/java/androidx/room/RoomWarnings.java b/room/common/src/main/java/androidx/room/RoomWarnings.java
index e8ad213..66cc1b8 100644
--- a/room/common/src/main/java/androidx/room/RoomWarnings.java
+++ b/room/common/src/main/java/androidx/room/RoomWarnings.java
@@ -134,6 +134,47 @@
public static final String RELATION_QUERY_WITHOUT_TRANSACTION =
"ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
+ /**
+ * Reported when an `@Entity` field's type do not exactly match the getter type.
+ * For instance, in the following class:
+ * <pre>
+ * {@code @}Entity
+ * class Foo {
+ * ...
+ * private Boolean value;
+ * public boolean getValue() {
+ * return value == null ? false : value;
+ * }
+ * }
+ * </pre>
+ *
+ * Trying to insert this entity into database will always set {@code value} column to
+ * {@code false} when {@code Foo.value} is {@code null} since Room will use the {@code getValue}
+ * method to read the value. So even thought the database column is nullable, it will never
+ * be inserted as {@code null} if inserted as a {@code Foo} instance.
+ */
+ public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+
+ /**
+ * Reported when an `@Entity` field's type do not exactly match the setter type.
+ * For instance, in the following class:
+ * <pre>
+ * {@code @}Entity
+ * class Foo {
+ * ...
+ * private Boolean value;
+ * public void setValue(boolean value) {
+ * this.value = value;
+ * }
+ * }
+ * </pre>
+ *
+ * If Room reads this entity from the database, it will always set {@code Foo.value} to
+ * {@code false} when the column value is {@code null} since Room will use the {@code setValue}
+ * method to write the value.
+ */
+ public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
+
/** @deprecated This type should not be instantiated as it contains only static methods. */
@Deprecated
@SuppressWarnings("PrivateConstructorForUtilityClass")
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
index 235a457..745c40f 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -718,6 +718,23 @@
context.checker.check(
success || bindingScope == FieldProcessor.BindingScope.READ_FROM_CURSOR,
field.element, CANNOT_FIND_GETTER_FOR_FIELD)
+ if (success && !context.processingEnv.typeUtils.isSameType(field.getter.type, field.type)) {
+ // getter's parameter type is not exactly the same as the field type.
+ // put a warning and update the value statement binder.
+ context.logger.w(
+ warning = Warning.MISMATCHED_GETTER_TYPE,
+ element = field.element,
+ msg = ProcessorErrors.mismatchedGetter(
+ fieldName = field.name,
+ ownerType = element.asType().typeName(),
+ getterType = field.getter.type.typeName(),
+ fieldType = field.typeName
+ ))
+ field.statementBinder = context.typeAdapterStore.findStatementValueBinder(
+ input = field.getter.type,
+ affinity = field.affinity
+ )
+ }
}
private fun assignSetters(
@@ -769,6 +786,23 @@
context.checker.check(
success || bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT,
field.element, CANNOT_FIND_SETTER_FOR_FIELD)
+ if (success && !context.processingEnv.typeUtils.isSameType(field.setter.type, field.type)) {
+ // setter's parameter type is not exactly the same as the field type.
+ // put a warning and update the value reader adapter.
+ context.logger.w(
+ warning = Warning.MISMATCHED_SETTER_TYPE,
+ element = field.element,
+ msg = ProcessorErrors.mismatchedSetter(
+ fieldName = field.name,
+ ownerType = element.asType().typeName(),
+ setterType = field.setter.type.typeName(),
+ fieldType = field.typeName
+ ))
+ field.cursorValueReader = context.typeAdapterStore.findCursorValueReader(
+ output = field.setter.type,
+ affinity = field.affinity
+ )
+ }
}
/**
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index d331aa1..d5b85f4 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -730,4 +730,26 @@
fun invalidChannelType(typeName: String) = "'$typeName' is not supported as a return type. " +
"Instead declare return type as ${KotlinTypeNames.FLOW} and use Flow transforming " +
"functions that converts the Flow into a Channel."
+
+ fun mismatchedGetter(
+ fieldName: String,
+ ownerType: TypeName,
+ getterType: TypeName,
+ fieldType: TypeName
+ ) = """
+ $ownerType's $fieldName field has type $fieldType but its getter returns $getterType.
+ This mismatch might cause unexpected $fieldName values in the database when $ownerType
+ is inserted into database.
+ """.trim()
+
+ fun mismatchedSetter(
+ fieldName: String,
+ ownerType: TypeName,
+ setterType: TypeName,
+ fieldType: TypeName
+ ) = """
+ $ownerType's $fieldName field has type $fieldType but its setter accepts $setterType.
+ This mismatch might cause unexpected $fieldName values when $ownerType is read from the
+ database.
+ """.trim()
}
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
index f9a5eaa..861fa1f 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
@@ -45,6 +45,14 @@
inTransaction: Boolean,
scope: CodeGenScope
) {
+ val cancellationSignalVar = scope.getTmpVar("_cancellationSignal")
+ scope.builder().addStatement(
+ "final $T $L = $T.createCancellationSignal()",
+ AndroidTypeNames.CANCELLATION_SIGNAL,
+ cancellationSignalVar,
+ RoomTypeNames.DB_UTIL
+ )
+
val callableImpl = CallableTypeSpecBuilder(typeArg.typeName()) {
createRunQueryAndReturnStatements(
builder = this,
@@ -58,10 +66,11 @@
scope.builder().apply {
addStatement(
- "return $T.execute($N, $L, $L, $N)",
+ "return $T.execute($N, $L, $L, $L, $N)",
RoomCoroutinesTypeNames.COROUTINES_ROOM,
dbField,
if (inTransaction) "true" else "false",
+ cancellationSignalVar,
callableImpl,
continuationParamName)
}
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
index 0abd15e9..f959979 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
@@ -36,7 +36,9 @@
DEFAULT_CONSTRUCTOR("ROOM_DEFAULT_CONSTRUCTOR"),
MISSING_COPY_ANNOTATIONS("MISSING_COPY_ANNOTATIONS"),
MISSING_INDEX_ON_JUNCTION("MISSING_INDEX_ON_JUNCTION"),
- JDK_VERSION_HAS_BUG("JDK_VERSION_HAS_BUG");
+ JDK_VERSION_HAS_BUG("JDK_VERSION_HAS_BUG"),
+ MISMATCHED_GETTER_TYPE("ROOM_MISMATCHED_GETTER_TYPE"),
+ MISMATCHED_SETTER_TYPE("ROOM_MISMATCHED_SETTER_TYPE");
companion object {
val PUBLIC_KEY_MAP = Warning.values().associateBy { it.publicKey }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
index 448ab8f..4ffb54a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
@@ -189,7 +189,10 @@
val constructorFields = node.directFields.filter {
it.field.setter.callType == CallType.CONSTRUCTOR
}.associateBy { fwi ->
- FieldReadWriteWriter(fwi).readIntoTmpVar(cursorVar, scope)
+ FieldReadWriteWriter(fwi).readIntoTmpVar(
+ cursorVar,
+ fwi.field.setter.type.typeName(),
+ scope)
}
// read decomposed fields (e.g. embedded)
node.subNodes.forEach(::visitNode)
@@ -349,9 +352,12 @@
/**
* Reads the value into a temporary local variable.
*/
- fun readIntoTmpVar(cursorVar: String, scope: CodeGenScope): String {
+ fun readIntoTmpVar(
+ cursorVar: String,
+ typeName: TypeName,
+ scope: CodeGenScope
+ ): String {
val tmpField = scope.getTmpVar("_tmp${field.name.capitalize()}")
- val typeName = field.getter.type.typeName()
scope.builder().apply {
addStatement("final $T $L", typeName, tmpField)
if (alwaysExists) {
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
index b9ec119..f9b4038 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
@@ -17,6 +17,7 @@
package androidx.room.processor
import COMMON
+import androidx.room.ext.typeName
import androidx.room.parser.SQLTypeAffinity
import androidx.room.processor.ProcessorErrors.RELATION_IN_ENTITY
import androidx.room.vo.CallType
@@ -28,6 +29,8 @@
import androidx.room.vo.Pojo
import androidx.room.vo.columnNames
import com.google.testing.compile.JavaFileObjects
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
import compileLibrarySource
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.hasItems
@@ -35,6 +38,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
+import java.lang.AssertionError
import javax.lang.model.type.TypeKind.INT
@RunWith(JUnit4::class)
@@ -141,6 +145,46 @@
}
@Test
+ fun setterWithAssignableType_2() {
+ singleEntity("""
+ @PrimaryKey
+ private Integer id;
+ public Integer getId() {return id;}
+ public void setId(int id) {}
+ """) { entity, invocation ->
+ val idField = entity.fields.first()
+ val cursorValueReader = idField.cursorValueReader
+ ?: throw AssertionError("must have a cursor value reader")
+ assertThat(cursorValueReader.typeMirror().typeName(),
+ `is`(invocation.typeUtils.getPrimitiveType(INT).typeName()))
+ }.compilesWithoutError()
+ .withWarningContaining(
+ ProcessorErrors.mismatchedSetter(
+ fieldName = "id",
+ ownerType = ClassName.bestGuess("foo.bar.MyEntity"),
+ setterType = TypeName.INT,
+ fieldType = TypeName.INT.box()
+ )
+ )
+ }
+
+ @Test
+ fun getterWithAssignableType_2() {
+ singleEntity("""
+ @PrimaryKey
+ private Integer id;
+ public int getId() {return id == null ? 0 : id;}
+ public void setId(Integer id) {}
+ """) { entity, invocation ->
+ val idField = entity.fields.first()
+ val statementBinder = idField.statementBinder
+ ?: throw AssertionError("must have a statement binder")
+ assertThat(statementBinder.typeMirror().typeName(),
+ `is`(invocation.typeUtils.getPrimitiveType(INT).typeName()))
+ }.compilesWithoutError()
+ }
+
+ @Test
fun noSetter() {
singleEntity("""
@PrimaryKey
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index 7e0f759..5f24684 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -75,6 +75,7 @@
androidTestImplementation(ANDROIDX_TEST_RUNNER)
androidTestImplementation(ANDROIDX_TEST_RULES)
androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(TRUTH)
androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java
new file mode 100644
index 0000000..fd2afd2
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2019 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.room.integration.testapp.test;
+
+import static androidx.room.integration.testapp.test.BoxedPrimitivesTest.BaseBoxed.DEFAULT_BOOLEAN_VALUE;
+import static androidx.room.integration.testapp.test.BoxedPrimitivesTest.BaseBoxed.DEFAULT_NUMBER_VALUE;
+
+import android.content.Context;
+
+import androidx.room.ColumnInfo;
+import androidx.room.Dao;
+import androidx.room.Database;
+import androidx.room.Entity;
+import androidx.room.Insert;
+import androidx.room.PrimaryKey;
+import androidx.room.Query;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.google.common.truth.Truth;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BoxedPrimitivesTest {
+ private BoxingTestDatabase mDb;
+
+ @Before
+ public void initDb() {
+ Context context = ApplicationProvider.getApplicationContext();
+ mDb = Room.inMemoryDatabaseBuilder(
+ context,
+ BoxingTestDatabase.class)
+ .build();
+ }
+
+ @After
+ public void closeDb() {
+ mDb.close();
+ }
+
+ @Test
+ public void unboxedConstructor() {
+ test(mDb.constructor());
+ }
+
+ @Test
+ public void unboxedGetter() {
+ test(mDb.field());
+ }
+
+ /**
+ * Assert that if a nullable pojo is provided, we can actually insert/read null
+ */
+ private void test(BaseDao<? extends BaseBoxed> dao) {
+ long rowId = dao.insert(new BoxedBooleanHolder(null, null));
+ BaseBoxed read = dao.find(rowId);
+ Truth.assertThat(read.mFlag).isNull();
+ Truth.assertThat(read.mNumber).isNull();
+ }
+
+ @Test
+ public void testInsert_constructor() {
+ long rowId = mDb.constructor().insertTyped(new ConstructorEntity(null, null));
+ testInsertedAsEntity(mDb.constructor(), rowId);
+ }
+
+ @Test
+ public void testInsert_field() {
+ long rowId = mDb.field().insertTyped(new FieldEntity());
+ testInsertedAsEntity(mDb.field(), rowId);
+ }
+
+ /**
+ * assert the case where row was inserted via entity hence we should've read the default values
+ * already.
+ **/
+ private void testInsertedAsEntity(BaseDao<? extends BaseBoxed> dao, long rowId) {
+ BaseBoxed read = dao.find(rowId);
+ // default getter value
+ Truth.assertThat(read.mFlag).isEqualTo(DEFAULT_BOOLEAN_VALUE);
+ Truth.assertThat(read.mNumber).isEqualTo(DEFAULT_NUMBER_VALUE);
+ }
+
+ static class BaseBoxed {
+ @ColumnInfo(name = "boxed_bool")
+ Boolean mFlag;
+ @ColumnInfo(name = "boxed_int")
+ Integer mNumber;
+
+ static final boolean DEFAULT_BOOLEAN_VALUE = true;
+ static final int DEFAULT_NUMBER_VALUE = 41;
+
+ @SuppressWarnings("unused")
+ boolean getFlag() {
+ return mFlag == null ? DEFAULT_BOOLEAN_VALUE : mFlag;
+ }
+
+ @SuppressWarnings("unused")
+ int getNumber() {
+ return mNumber == null ? DEFAULT_NUMBER_VALUE : mNumber;
+ }
+ }
+
+ @Entity
+ static class ConstructorEntity extends BaseBoxed {
+ @PrimaryKey(autoGenerate = true)
+ public long rowId = 0;
+
+ ConstructorEntity(Boolean flag, Integer number) {
+ this.mFlag = flag;
+ this.mNumber = number;
+ }
+ }
+
+ @Entity
+ static class FieldEntity extends BaseBoxed {
+ @PrimaryKey(autoGenerate = true)
+ public long rowId = 0;
+
+ void setBoxed(Boolean boxed) {
+ this.mFlag = boxed;
+ }
+
+ void setNumber(Integer number) {
+ this.mNumber = number;
+ }
+ }
+
+ static class BoxedBooleanHolder {
+ @ColumnInfo(name = "boxed_bool")
+ final Boolean mFlag;
+ @ColumnInfo(name = "boxed_int")
+ final Integer mNumber;
+
+ BoxedBooleanHolder(Boolean flag, Integer number) {
+ mFlag = flag;
+ mNumber = number;
+ }
+ }
+
+ interface BaseDao<T> {
+ long insert(BoxedBooleanHolder t);
+
+ @Insert
+ long insertTyped(T t);
+
+ T find(long rowId);
+ }
+
+ @Dao
+ interface BoxedConstructorDao extends BaseDao<ConstructorEntity> {
+ @Override
+ @Insert(entity = ConstructorEntity.class)
+ long insert(BoxedBooleanHolder item);
+
+ @Override
+ @Query("SELECT * FROM ConstructorEntity WHERE rowId = :rowId")
+ ConstructorEntity find(long rowId);
+ }
+
+ @Dao
+ interface BoxedFieldDao extends BaseDao<FieldEntity> {
+
+ @Insert(entity = FieldEntity.class)
+ long insert(BoxedBooleanHolder item);
+
+ @Override
+ @Query("SELECT * FROM FieldEntity WHERE rowId = :rowId")
+ FieldEntity find(long rowId);
+ }
+
+ @Database(
+ entities = {FieldEntity.class, ConstructorEntity.class},
+ version = 1,
+ exportSchema = false
+ )
+ abstract static class BoxingTestDatabase extends RoomDatabase {
+ abstract BoxedConstructorDao constructor();
+
+ abstract BoxedFieldDao field();
+ }
+}
diff --git a/room/ktx/api/restricted_2.3.0-alpha01.txt b/room/ktx/api/restricted_2.3.0-alpha01.txt
index 20837edc..289fdbe 100644
--- a/room/ktx/api/restricted_2.3.0-alpha01.txt
+++ b/room/ktx/api/restricted_2.3.0-alpha01.txt
@@ -4,12 +4,14 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class CoroutinesRoom {
method public static <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, java.util.concurrent.Callable<R> inTransaction, kotlin.coroutines.Continuation<? super R> callable);
+ method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, android.os.CancellationSignal inTransaction, java.util.concurrent.Callable<R> cancellationSignal, kotlin.coroutines.Continuation<? super R> callable);
field public static final androidx.room.CoroutinesRoom.Companion! Companion;
}
public static final class CoroutinesRoom.Companion {
method public <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
+ method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, android.os.CancellationSignal cancellationSignal, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
}
public final class CoroutinesRoomKt {
diff --git a/room/ktx/api/restricted_current.txt b/room/ktx/api/restricted_current.txt
index 20837edc..289fdbe 100644
--- a/room/ktx/api/restricted_current.txt
+++ b/room/ktx/api/restricted_current.txt
@@ -4,12 +4,14 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class CoroutinesRoom {
method public static <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, java.util.concurrent.Callable<R> inTransaction, kotlin.coroutines.Continuation<? super R> callable);
+ method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, android.os.CancellationSignal inTransaction, java.util.concurrent.Callable<R> cancellationSignal, kotlin.coroutines.Continuation<? super R> callable);
field public static final androidx.room.CoroutinesRoom.Companion! Companion;
}
public static final class CoroutinesRoom.Companion {
method public <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
+ method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, android.os.CancellationSignal cancellationSignal, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
}
public final class CoroutinesRoomKt {
diff --git a/room/ktx/build.gradle b/room/ktx/build.gradle
index 5d5528b..38b18eb 100644
--- a/room/ktx/build.gradle
+++ b/room/ktx/build.gradle
@@ -35,6 +35,12 @@
testImplementation(MOCKITO_CORE)
testImplementation(TRUTH)
testImplementation("androidx.lifecycle:lifecycle-livedata-core:2.0.0")
+ testImplementation(ANDROIDX_TEST_RUNNER)
+ testImplementation(KOTLIN_COROUTINES_TEST)
+
+ androidTestImplementation(TRUTH)
+ androidTestImplementation(ANDROIDX_TEST_RUNNER)
+ androidTestImplementation(KOTLIN_COROUTINES_TEST)
}
androidx {
diff --git a/room/ktx/src/androidTest/java/androidx/room/CoroutineRoomCancellationTest.kt b/room/ktx/src/androidTest/java/androidx/room/CoroutineRoomCancellationTest.kt
new file mode 100644
index 0000000..b340852
--- /dev/null
+++ b/room/ktx/src/androidTest/java/androidx/room/CoroutineRoomCancellationTest.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2019 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.room
+
+import android.database.sqlite.SQLiteException
+import android.os.CancellationSignal
+import androidx.sqlite.db.SupportSQLiteOpenHelper
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineDispatcher
+import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Test
+import java.util.concurrent.Callable
+import java.util.concurrent.CountDownLatch
+
+@SmallTest
+@SdkSuppress(minSdkVersion = 16)
+@ExperimentalCoroutinesApi
+class CoroutineRoomCancellationTest {
+
+ private val testDispatcher = TestCoroutineDispatcher()
+ val testScope = TestCoroutineScope(testDispatcher)
+
+ private val database = TestDatabase()
+
+ @Test
+ fun testSuspend_cancellable_duringLongQuery() = runBlocking {
+ database.backingFieldMap["QueryDispatcher"] = Dispatchers.IO
+
+ val inQueryLatch = CountDownLatch(1)
+ val cancelledLatch = CountDownLatch(1)
+
+ val cancellationSignal = CancellationSignal()
+ cancellationSignal.setOnCancelListener {
+ // query was cancelled so now we can finish our test
+ cancelledLatch.countDown()
+ }
+
+ val job = GlobalScope.launch(Dispatchers.IO) {
+ CoroutinesRoom.execute(
+ db = database,
+ inTransaction = false,
+ cancellationSignal = cancellationSignal,
+ callable = Callable {
+ // we're triggering our fake query
+ inQueryLatch.countDown()
+ // fake a long query so we can cancel
+ cancelledLatch.await()
+ }
+ )
+ }
+ inQueryLatch.await()
+ // we're in the query so we can cancel
+ job.cancelAndJoin()
+
+ assertThat(cancellationSignal.isCanceled).isTrue()
+ }
+
+ @Test
+ fun testSuspend_cancellable_beforeQueryStarts() = runBlocking {
+ database.backingFieldMap["QueryDispatcher"] = testDispatcher
+
+ val inCoroutineLatch = CountDownLatch(1)
+ val cancelledLatch = CountDownLatch(1)
+
+ val cancellationSignal = CancellationSignal()
+ cancellationSignal.setOnCancelListener {
+ // query was cancelled so now we can finish our test
+ cancelledLatch.countDown()
+ }
+
+ val job = GlobalScope.launch(Dispatchers.IO) {
+ // Coroutine started so now we can cancel it
+ inCoroutineLatch.countDown()
+
+ // We're using a different dispatcher for queries.
+ // Pausing it, to simulate that we're cancelling the query before it's triggered
+ testDispatcher.pauseDispatcher()
+ CoroutinesRoom.execute(
+ db = database,
+ inTransaction = false,
+ cancellationSignal = cancellationSignal,
+ callable = Callable {
+ // this should never execute
+ fail("Blocking query triggered")
+ }
+ )
+ }
+ inCoroutineLatch.await()
+ job.cancelAndJoin()
+ testDispatcher.resumeDispatcher()
+
+ assertThat(cancellationSignal.isCanceled).isTrue()
+ }
+
+ @Test
+ fun testSuspend_exception_in_query() = runBlocking {
+ database.backingFieldMap["QueryDispatcher"] = Dispatchers.IO
+ val cancellationSignal = CancellationSignal()
+
+ GlobalScope.launch(Dispatchers.IO) {
+ try {
+ CoroutinesRoom.execute(
+ db = database,
+ inTransaction = false,
+ cancellationSignal = cancellationSignal,
+ callable = Callable {
+ throw SQLiteException("stuff happened")
+ }
+ )
+ } catch (exception: Throwable) {
+ assertTrue(exception is SQLiteException)
+ }
+ }
+
+ assertThat(cancellationSignal.isCanceled).isFalse()
+ }
+
+ @Test
+ fun testSuspend_notCancelled() = runBlocking {
+ database.backingFieldMap["QueryDispatcher"] = testDispatcher
+
+ val cancellationSignal = CancellationSignal()
+
+ val job = testScope.launch {
+ CoroutinesRoom.execute(
+ db = database,
+ inTransaction = false,
+ cancellationSignal = cancellationSignal,
+ callable = Callable { /* nothing to do */ }
+ )
+ }
+ // wait for the job to be finished
+ job.join()
+
+ assertThat(cancellationSignal.isCanceled).isFalse()
+ }
+
+ private class TestDatabase : RoomDatabase() {
+
+ override fun createOpenHelper(config: DatabaseConfiguration?): SupportSQLiteOpenHelper {
+ throw UnsupportedOperationException("Shouldn't be called!")
+ }
+
+ override fun createInvalidationTracker(): InvalidationTracker {
+ return TestInvalidationTracker(this)
+ }
+
+ override fun clearAllTables() {
+ throw UnsupportedOperationException("Shouldn't be called!")
+ }
+ }
+
+ private class TestInvalidationTracker(db: RoomDatabase) : InvalidationTracker(db) {
+ val observers = mutableListOf<Observer>()
+
+ override fun addObserver(observer: Observer) {
+ observers.add(observer)
+ }
+
+ override fun removeObserver(observer: Observer) {
+ observers.remove(observer)
+ }
+ }
+}
diff --git a/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt b/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt
index c7befed..83613d5 100644
--- a/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt
+++ b/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt
@@ -16,15 +16,22 @@
package androidx.room
+import android.os.Build
+import android.os.CancellationSignal
import androidx.annotation.RestrictTo
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import java.util.concurrent.Callable
import kotlin.coroutines.coroutineContext
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
/**
* A helper class for supporting Kotlin Coroutines in Room.
@@ -56,6 +63,39 @@
}
@JvmStatic
+ suspend fun <R> execute(
+ db: RoomDatabase,
+ inTransaction: Boolean,
+ cancellationSignal: CancellationSignal,
+ callable: Callable<R>
+ ): R {
+ if (db.isOpen && db.inTransaction()) {
+ return callable.call()
+ }
+
+ // Use the transaction dispatcher if we are on a transaction coroutine, otherwise
+ // use the database dispatchers.
+ val context = coroutineContext[TransactionElement]?.transactionDispatcher
+ ?: if (inTransaction) db.transactionDispatcher else db.queryDispatcher
+ return suspendCancellableCoroutine<R> { continuation ->
+ val job = GlobalScope.launch(context) {
+ try {
+ val result = callable.call()
+ continuation.resume(result)
+ } catch (exception: Throwable) {
+ continuation.resumeWithException(exception)
+ }
+ }
+ continuation.invokeOnCancellation {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ cancellationSignal.cancel()
+ }
+ job.cancel()
+ }
+ }
+ }
+
+ @JvmStatic
fun <R> createFlow(
db: RoomDatabase,
inTransaction: Boolean,
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
index 9dc8227..92ed977 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
@@ -19,6 +19,7 @@
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.selection.ItemDetailsLookup;
import androidx.recyclerview.widget.RecyclerView;
@@ -36,7 +37,7 @@
}
@Override
- public ItemDetails<Uri> getItemDetails(MotionEvent e) {
+ public ItemDetails<Uri> getItemDetails(@NonNull MotionEvent e) {
@Nullable View view = mRecView.findChildViewUnder(e.getX(), e.getY());
if (view != null) {
ViewHolder holder = mRecView.getChildViewHolder(view);
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
index a145403..6637d88 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
@@ -54,12 +54,12 @@
}
@Override
- public boolean inDragRegion(MotionEvent e) {
+ public boolean inDragRegion(@NonNull MotionEvent e) {
return FancyHolder.this.inDragRegion(e);
}
@Override
- public boolean inSelectionHotspot(MotionEvent e) {
+ public boolean inSelectionHotspot(@NonNull MotionEvent e) {
return FancyHolder.this.inSelectRegion(e);
}
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 27a3b04..c54368b 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
@@ -18,6 +18,7 @@
import android.content.Context;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
@@ -30,6 +31,7 @@
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
import androidx.recyclerview.selection.ItemKeyProvider;
@@ -83,9 +85,9 @@
mSelectionTracker = builder
.withSelectionPredicate(SelectionPredicates.createSelectAnything())
.withOnDragInitiatedListener(new OnDragInitiatedListener(this))
- .withOnContextClickListener(new OnContextClickListener(this))
+ .withOnContextClickListener(new OnContextClickListener())
.withOnItemActivatedListener(new OnItemActivatedListener(this))
- .withFocusDelegate(new FocusDelegate(this))
+ .withFocusDelegate(new FocusDelegate())
.withBandOverlay(R.drawable.selection_demo_band_overlay)
.build();
@@ -107,7 +109,7 @@
}
@Override
- protected void onSaveInstanceState(Bundle state) {
+ protected void onSaveInstanceState(@NonNull Bundle state) {
super.onSaveInstanceState(state);
mSelectionTracker.onSaveInstanceState(state);
state.putInt(EXTRA_COLUMN_COUNT, mColumnCount);
@@ -219,15 +221,10 @@
private static final class FocusDelegate extends
androidx.recyclerview.selection.FocusDelegate<Uri> {
- private final Context mContext;
private ItemDetails<Uri> mFocusedItem;
- private FocusDelegate(Context context) {
- mContext = context;
- }
-
@Override
- public void focusItem(ItemDetails<Uri> item) {
+ public void focusItem(@NonNull ItemDetails<Uri> item) {
mFocusedItem = item;
Log.i(TAG, "focusItem called for " + item);
}
@@ -269,14 +266,7 @@
private final class OnContextClickListener implements
androidx.recyclerview.selection.OnContextClickListener {
- private boolean mShowByViewHolder;
-
- private final Context mContext;
-
- OnContextClickListener(Context context) {
- mContext = context;
- }
-
+ @RequiresApi(api = Build.VERSION_CODES.N)
@Override
public boolean onContextClick(MotionEvent e) {
View view = mRecView.findChildViewUnder(e.getX(), e.getY());
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java
index 81bda7f..51e39c1 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java
@@ -18,6 +18,7 @@
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.selection.ItemDetailsLookup;
import androidx.recyclerview.widget.RecyclerView;
@@ -35,7 +36,7 @@
}
@Override
- public ItemDetails<Long> getItemDetails(MotionEvent e) {
+ public ItemDetails<Long> getItemDetails(@NonNull MotionEvent e) {
@Nullable View view = mRecView.findChildViewUnder(e.getX(), e.getY());
if (view != null) {
ViewHolder holder = mRecView.getChildViewHolder(view);
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
index ad28e23..9759905 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
@@ -20,6 +20,7 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
import androidx.recyclerview.widget.RecyclerView;
@@ -49,12 +50,12 @@
}
@Override
- public boolean inDragRegion(MotionEvent e) {
+ public boolean inDragRegion(@NonNull MotionEvent e) {
return DemoHolder.this.inDragRegion(e);
}
@Override
- public boolean inSelectionHotspot(MotionEvent e) {
+ public boolean inSelectionHotspot(@NonNull MotionEvent e) {
return DemoHolder.this.inSelectRegion(e);
}
};
diff --git a/serialization/serialization-schema/build.gradle b/serialization/serialization-schema/build.gradle
index d6a7de9..c361ea0 100644
--- a/serialization/serialization-schema/build.gradle
+++ b/serialization/serialization-schema/build.gradle
@@ -27,6 +27,7 @@
}
dependencies {
+ api(project(":serialization:serialization-annotation"))
implementation(KOTLIN_STDLIB)
testImplementation(JUNIT)
}
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Reserved.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Reserved.kt
new file mode 100644
index 0000000..de20f52
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Reserved.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.serialization.schema
+
+/**
+ * A collection of reserved IDs or names for a message class, enum class, or service interface.
+ *
+ * @property ids Message field, enum value, or service action IDs to reserve.
+ * @property names Message field, enum value, or service action names to reserve.
+ * @property idRanges Ranges of IDs to reserve in bulk.
+ * @see androidx.serialization.Reserved
+ */
+data class Reserved(
+ val ids: Set<Int> = emptySet(),
+ val names: Set<String> = emptySet(),
+ val idRanges: Set<IntRange> = emptySet()
+) {
+ operator fun contains(id: Int): Boolean {
+ return id in ids || idRanges.any { id in it }
+ }
+
+ operator fun contains(name: String): Boolean {
+ return name in names
+ }
+
+ companion object {
+ private val EMPTY_INSTANCE = Reserved()
+
+ fun empty(): Reserved = EMPTY_INSTANCE
+ }
+}
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Schema.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Schema.kt
new file mode 100644
index 0000000..e7d6c73
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Schema.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 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.serialization.schema
+
+/**
+ * A schema consisting of messages, enums, and services.
+ *
+ * Clients who have subclassed [Message], [Enum], or [Service] may wish to subclass this class to
+ * provide type safety around their subclassed types.
+ *
+ * @property messages Messages declared in the schema.
+ * @property enums Enums declared in the schema.
+ * @property services Services declared in the schema.
+ */
+open class Schema(
+ open val messages: List<Message> = emptyList(),
+ open val enums: List<Enum> = emptyList(),
+ open val services: List<Service> = emptyList()
+)
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Type.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Type.kt
new file mode 100644
index 0000000..aebd8fc
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Type.kt
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2019 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.serialization.schema
+
+import androidx.serialization.ProtoEncoding
+import androidx.serialization.ProtoEncoding.SIGNED_FIXED
+import androidx.serialization.ProtoEncoding.SIGNED_VARINT
+import androidx.serialization.ProtoEncoding.UNSIGNED_FIXED
+import androidx.serialization.ProtoEncoding.UNSIGNED_VARINT
+import androidx.serialization.ProtoEncoding.ZIG_ZAG_VARINT
+
+/**
+ * Root of the serialization type hierarchy.
+ */
+sealed class Type
+
+// Declared Types ////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A user-declared message, enum, or service.
+ *
+ * @property name The qualified name of the type.
+ * @property members Members of the type, such as message fields, enum values, or service actions.
+ * @property reserved Reserved IDs and names within this type
+ */
+sealed class DeclaredType(
+ val name: TypeName,
+ val members: List<Member>,
+ val reserved: Reserved
+) : Type() {
+ /**
+ * A member of a user-declared type, such as a message field, enum value, or service action.
+ */
+ abstract class Member(
+ val id: Int,
+ val name: String
+ )
+}
+
+/**
+ * A user-declared message.
+ *
+ * Clients of this package may wish to subclass [Message] and [Field] to add additional context
+ * or data such as source location.
+ *
+ * @property fields Fields of the message.
+ *
+ * Consider overriding this property in a subclass if you subclass [Field].
+ */
+open class Message(
+ name: TypeName,
+ open val fields: List<Field>,
+ reserved: Reserved = Reserved.empty()
+) : DeclaredType(name, fields, reserved) {
+ /**
+ * A field of a user-declared message.
+ *
+ * @property type The type of the field, may be any type starting from root.
+ * @see androidx.serialization.Field
+ */
+ open class Field(
+ id: Int,
+ name: String,
+ val type: Type
+ ) : Member(id, name)
+}
+
+/**
+ * A user-declared serializable enum.
+ *
+ * Clients of this package may wish to subclass [Enum] and [Value] to add additional context
+ * or data such as source location.
+ *
+ * @property values Values of the enum.
+ *
+ * Consider overriding this property in a subclass if you subclass [Value].
+ */
+open class Enum(
+ name: TypeName,
+ open val values: List<Value>,
+ reserved: Reserved = Reserved.empty()
+) : DeclaredType(name, values, reserved) {
+ /**
+ * A value of a user-declared enum.
+ *
+ * @see androidx.serialization.EnumValue
+ */
+ open class Value(
+ id: Int,
+ name: String
+ ) : Member(id, name)
+}
+
+/**
+ * A user-declared service interface.
+ *
+ * Clients of this package may wish to subclass [Service] and [Action] to add additional context
+ * or data such as source location.
+ *
+ * @property actions Actions of the service.
+ *
+ * Consider overriding this property in a subclass if you subclass [Action].
+ */
+open class Service(
+ name: TypeName,
+ open val actions: List<Action>,
+ reserved: Reserved = Reserved.empty()
+) : DeclaredType(name, actions, reserved) {
+ /**
+ * An action of a user-declared service interface.
+ *
+ * Consider overriding [request] and [response] if you subclass [Message].
+ *
+ * @property request The request message type, or null for a nullary action method.
+ * @property response The response message type, or null for a void action method.
+ * @property mode The synchronization mode of the action.
+ * @see androidx.serialization.Action
+ */
+ open class Action(
+ id: Int,
+ name: String,
+ open val request: Message? = null,
+ open val response: Message? = null,
+ val mode: Mode = Mode.BLOCKING
+ ) : Member(id, name) {
+ /**
+ * The synchronization mode of an action.
+ */
+ enum class Mode {
+ /**
+ * Action method blocks until transaction completes on remote process.
+ */
+ BLOCKING,
+
+ /**
+ * Action method returns immediately and does not return a response.
+ *
+ * @see android.os.IBinder.FLAG_ONEWAY
+ */
+ ONE_WAY
+ }
+ }
+}
+
+// Collections ///////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A linear collection of values, such as a [Collection] or an [Array].
+ */
+open class CollectionType(val type: Type) : Type()
+
+/**
+ * An associative collection of keys and values, such as a [Map] or a [android.util.SparseArray].
+ */
+open class MapType(val keyType: Type, val valueType: Type) : Type()
+
+// Scalars ///////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A scalar value.
+ *
+ * Scalar fields have a default value of zero, empty, or false.
+ *
+ * @property name Scalar name, as used in proto.
+ * @property protoEncoding Proto encoding of integral scalar values.
+ */
+sealed class Scalar(
+ val name: String,
+ val protoEncoding: ProtoEncoding = ProtoEncoding.DEFAULT
+) : Type()
+
+/**
+ * Boolean scalar.
+ */
+object BoolScalar : Scalar("bool")
+
+/**
+ * Byte array scalar, such as [ByteArray] or [java.nio.ByteBuffer].
+ */
+object BytesScalar : Scalar("bytes")
+
+/**
+ * A 64-bit floating point scalar.
+ */
+object DoubleScalar : Scalar("double")
+
+/**
+ * A 32-bit floating point scalar.
+ */
+object FloatScalar : Scalar("float")
+
+/**
+ * String scalar.
+ */
+object StringScalar : Scalar("string")
+
+/**
+ * A 32-bit integer scalar type.
+ */
+sealed class IntScalar(name: String, protoEncoding: ProtoEncoding) : Scalar(name, protoEncoding)
+
+/**
+ * A 32-bit signed integer scalar using the [SIGNED_VARINT] encoding.
+ */
+object Int32Scalar : IntScalar("int32", SIGNED_VARINT)
+
+/**
+ * A 32-bit signed integer scalar using the [ZIG_ZAG_VARINT] encoding.
+ */
+object SInt32Scalar : IntScalar("sint32", ZIG_ZAG_VARINT)
+
+/**
+ * A 32-bit unsigned integer scalar using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt32Scalar : IntScalar("uint32", UNSIGNED_VARINT)
+
+/**
+ * A 32-bit unsigned fixed width integer scalar.
+ */
+object Fixed32Scalar : IntScalar("fixed32", UNSIGNED_FIXED)
+
+/**
+ * A 32-bit signed fixed width integer scalar.
+ */
+object SFixed32Scalar : IntScalar("sfixed32", SIGNED_FIXED)
+
+/**
+ * A 64-bit integer scalar type.
+ */
+sealed class LongScalar(name: String, protoEncoding: ProtoEncoding) : Scalar(name, protoEncoding)
+
+/**
+ * A 64-bit signed integer scalar using the [SIGNED_VARINT] encoding.
+ */
+object Int64Scalar : LongScalar("int64", SIGNED_VARINT)
+
+/**
+ * A 64-bit signed integer scalar using the [ZIG_ZAG_VARINT] encoding.
+ */
+object SInt64Scalar : LongScalar("sint64", ZIG_ZAG_VARINT)
+
+/**
+ * A 64-bit unsigned integer scalar using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt64Scalar : LongScalar("uint64", UNSIGNED_VARINT)
+
+/**
+ * A 64-bit unsigned fixed width integer scalar.
+ */
+object Fixed64Scalar : LongScalar("fixed64", UNSIGNED_FIXED)
+
+/**
+ * A 64-bit signed fixed width integer scalar.
+ */
+object SFixed64Scalar : LongScalar("sfixed64", SIGNED_FIXED)
+
+// Wrapper Messages //////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A message type that wraps a scalar value.
+ *
+ * This provides support for nullable field types. The message types are derived from proto's
+ * [well known types][1].
+ *
+ * [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
+ *
+ * @property scalar The wrapped scalar type.
+ */
+sealed class Wrapper(simpleName: String, val scalar: Scalar) : Type() {
+ /**
+ * The name of the type in the `google.protobuf` package.
+ */
+ val name = TypeName("google.protobuf", simpleName)
+}
+
+/**
+ * Boolean wrapper message.
+ */
+object BoolWrapper : Wrapper("BoolWrapper", BoolScalar)
+
+/**
+ * Bytes wrapper message, such as a nullable [ByteArray] or [java.nio.ByteBuffer].
+ */
+object BytesWrapper : Wrapper("BytesValue", BytesScalar)
+
+/**
+ * A 64-bit floating point wrapper message.
+ */
+object DoubleWrapper : Wrapper("DoubleValue", DoubleScalar)
+
+/**
+ * A 32-bit floating point wrapper message.
+ */
+object FloatWrapper : Wrapper("FloatValue", FloatScalar)
+
+/**
+ * String wrapper message.
+ */
+object StringWrapper : Wrapper("StringValue", StringScalar)
+
+/**
+ * A 32-bit integer wrapper message type.
+ */
+sealed class IntWrapper(name: String, scalar: IntScalar) : Wrapper(name, scalar)
+
+/**
+ * A signed 32-bit integer wrapper message using the [SIGNED_VARINT] encoding.
+ */
+object Int32Wrapper : IntWrapper("Int32Value", Int32Scalar)
+
+/**
+ * An unsigned 32-bit integer wrapper message using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt32Wrapper : IntWrapper("UInt32Value", UInt32Scalar)
+
+/**
+ * A 64-bit integer wrapper message type.
+ */
+sealed class LongWrapper(name: String, scalar: LongScalar) : Wrapper(name, scalar)
+
+/**
+ * A signed 64-bit integer wrapper message using the [SIGNED_VARINT] encoding.
+ */
+object Int64Wrapper : LongWrapper("Int64Value", Int64Scalar)
+
+/**
+ * An unsigned 64-bit integer wrapper message using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt64Wrapper : LongWrapper("UInt64Value", UInt64Scalar)
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/TypeName.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/TypeName.kt
new file mode 100644
index 0000000..706311e
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/TypeName.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 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.serialization.schema
+
+/**
+ * The qualified name of a declared, wrapper, or well-known type.
+ *
+ * For example, the nested enum class `Bar` below would be represented as
+ * `TypeName("com.example", "Foo", "Bar")`
+ *
+ * ```kotlin
+ * package com.example
+ *
+ * data class Foo(@Field(1) val bar: Bar) {
+ * enum class Bar {
+ * @EnumValue(0)
+ * ZERO,
+ * @EnumValue(1)
+ * ONE
+ * }
+ * }
+ * ```
+ *
+ * @property packageName The package containing the type, or null for the default package.
+ * @property names A list of nested type names.
+ */
+class TypeName(
+ packageName: String? = null,
+ val names: List<String>
+) {
+ init {
+ require(names.isNotEmpty()) { "names must contain at least one name" }
+ require(names.none { it.isEmpty() }) {
+ "names must not contain empty names. names: $names"
+ }
+ }
+
+ constructor(
+ packageName: String?,
+ vararg names: String
+ ) : this(packageName, names.asList())
+
+ val packageName: String? = packageName?.ifEmpty { null }
+
+ /**
+ * The simple name of the type.
+ *
+ * For `com.example.Foo.Bar`, this is `Bar`.
+ */
+ val simpleName: String = names.last()
+
+ /**
+ * The canonical name of the type, separated with dots.
+ */
+ val canonicalName: String by lazy {
+ buildString {
+ if (packageName != null) {
+ append(packageName)
+ append(".")
+ }
+ names.joinTo(this, ".")
+ }
+ }
+
+ override fun toString(): String = canonicalName
+
+ override fun hashCode(): Int {
+ return (packageName.hashCode() * 31) + names.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return when (other) {
+ is TypeName -> this.packageName == other.packageName && this.names == other.names
+ else -> false
+ }
+ }
+}
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/ReservedTest.kt b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/ReservedTest.kt
new file mode 100644
index 0000000..9d780e7
--- /dev/null
+++ b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/ReservedTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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.serialization.schema
+
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+/**
+ * Tests for [Reserved].
+ */
+class ReservedTest {
+ @Test
+ fun testContainsIds() {
+ val reserved = Reserved(ids = setOf(1, 2))
+ assertTrue(1 in reserved)
+ assertTrue(2 in reserved)
+ assertFalse(3 in reserved)
+ }
+
+ @Test
+ fun testContainsNames() {
+ val reserved = Reserved(names = setOf("foo", "bar"))
+ assertTrue("foo" in reserved)
+ assertTrue("bar" in reserved)
+ assertFalse("quux" in reserved)
+ }
+
+ @Test
+ fun testContainsIdRanges() {
+ val reserved = Reserved(idRanges = setOf(1..10, 21..40))
+
+ for (i in 1..10) {
+ assertTrue(i in reserved)
+ }
+
+ for (i in 11..20) {
+ assertFalse(i in reserved)
+ }
+
+ for (i in 21..40) {
+ assertTrue(i in reserved)
+ }
+ }
+}
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/TypeNameTest.kt b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/TypeNameTest.kt
new file mode 100644
index 0000000..75adb3c
--- /dev/null
+++ b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/TypeNameTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019 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.serialization.schema
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+/**
+ * Tests for [TypeName].
+ */
+class TypeNameTest {
+ @Test(expected = IllegalArgumentException::class)
+ fun testAtLeastOneNameRequirement() {
+ TypeName("com.example", emptyList())
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun testNonEmptyNameRequirement() {
+ TypeName("com.example", "Foo", "", "Bar")
+ }
+
+ @Test
+ fun testDefaultNullPackage() {
+ assertNull(TypeName(names = listOf("Foo")).packageName)
+ }
+
+ @Test
+ fun testEmptyPackageName() {
+ assertNull(TypeName("", "Foo").packageName)
+ }
+
+ @Test
+ fun testCanonicalNameSingle() {
+ assertEquals("com.example.Foo", TypeName("com.example", "Foo").canonicalName)
+ }
+
+ @Test
+ fun testCanonicalNameNested() {
+ assertEquals("com.example.Foo.Bar", TypeName("com.example", "Foo", "Bar").canonicalName)
+ }
+
+ @Test
+ fun testCanonicalNameNullPackage() {
+ assertEquals("Foo", TypeName(null, "Foo").canonicalName)
+ }
+
+ @Test
+ fun testSimpleNameSingle() {
+ assertEquals("Foo", TypeName("com.example", "Foo").simpleName)
+ }
+
+ @Test
+ fun testSimpleNameNested() {
+ assertEquals("Bar", TypeName("com.example", "Foo", "Bar").simpleName)
+ }
+
+ @Test
+ fun testToString() {
+ val name = TypeName("com.example", "Foo", "Bar")
+ assertEquals(name.canonicalName, name.toString())
+ }
+
+ @Test
+ fun testHashCode() {
+ val a = TypeName("com.example", "Foo")
+ val b = TypeName("com.example", "Foo")
+ val c = TypeName("com.example", "Bar")
+
+ assertEquals(a.hashCode(), b.hashCode())
+ assertNotEquals(a.hashCode(), c.hashCode())
+ }
+
+ @Test
+ fun testEquals() {
+ val a = TypeName("com.example", "Foo")
+ val b = TypeName("com.example", "Foo")
+ val c = TypeName("com.example", "Bar")
+
+ assertTrue(a == b)
+ assertTrue(b == a)
+ assertFalse(a == c)
+ assertFalse(c == a)
+ }
+}
\ No newline at end of file
diff --git a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
index 2d75deb..f0c401b7 100644
--- a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
+++ b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
@@ -59,6 +59,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
+import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
@@ -806,13 +807,18 @@
IconCompat icon = IconCompat.createWithResource(getContext(), R.drawable.ic_star_on);
SliceAction primaryAction = SliceAction.create(
getBroadcastIntent(ACTION_TOAST, "open download"), icon, ICON_IMAGE, "Download");
+ int progress = PROGRESS.next();
+ if (progress != 100) {
+ mHandler.postDelayed(() -> getContext().getContentResolver().notifyChange(sliceUri,
+ null), 500);
+ }
return new ListBuilder(getContext(), sliceUri, INFINITY)
.setAccentColor(0xffff4081)
.addRange(new RangeBuilder()
.setTitle("Download progress")
.setSubtitle("Download is happening")
.setMax(100)
- .setValue(75)
+ .setValue(progress)
.setPrimaryAction(primaryAction))
.build();
}
@@ -1185,4 +1191,18 @@
return PendingIntent.getBroadcast(getContext(), requestCode, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
+
+ static final class RandomProgressGenerator {
+ private int mProgress = 0;
+ private int mEnd = 100;
+ private int mInterval = 5;
+
+ int next() {
+ if (mProgress >= mEnd) return mEnd;
+ mProgress += new Random().nextInt(mInterval);
+ return Math.min(mEnd, mProgress);
+ }
+ }
+
+ private static final RandomProgressGenerator PROGRESS = new RandomProgressGenerator();
}
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index 56808ef..3fe3367 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -78,6 +78,7 @@
import androidx.annotation.RestrictTo;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.graphics.drawable.IconCompat;
+import androidx.core.view.ViewCompat;
import androidx.slice.SliceItem;
import androidx.slice.SliceStructure;
import androidx.slice.core.SliceAction;
@@ -195,6 +196,9 @@
mActionSpinner = findViewById(R.id.action_sent_indicator);
SliceViewUtil.tintIndeterminateProgressBar(getContext(), mActionSpinner);
mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
+ ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ ViewCompat.setImportantForAccessibility(
+ mContent, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
@Override
@@ -557,6 +561,12 @@
&& mLoadingActions.contains(mRowAction.getSliceItem())) {
mShowActionSpinner = true;
}
+
+ ViewCompat.setImportantForAccessibility(mRootView,
+ (mRootView.isClickable() && mToggles.isEmpty() && mActions.isEmpty())
+ ? ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO
+ : ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO
+ );
}
@Override
diff --git a/ui/gradle.properties b/ui/gradle.properties
index 799d540..39f2467 100644
--- a/ui/gradle.properties
+++ b/ui/gradle.properties
@@ -12,3 +12,5 @@
// Run multiple kotlin compilations in parallel within the same project.
// See also https://github.com/JetBrains/kotlin/blob/1978db9d0e68a2ec29aded30a07e9c3c740c29f6/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt#L100 and https://blog.jetbrains.com/kotlin/2019/01/kotlin-1-3-20-released/
kotlin.parallel.tasks.in.project=true
+# TODO(b/144189353) : remove android.useNewJarCreator once it stops putting illegal timestamps into jars
+android.useNewJarCreator=false
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt
index 374552e..cd8e9029 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt
@@ -25,13 +25,13 @@
import androidx.ui.foundation.ColoredRect
import androidx.ui.graphics.Color
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.FlexColumn
import androidx.ui.foundation.HorizontalScroller
import androidx.ui.layout.Row
import androidx.ui.foundation.ScrollerPosition
import androidx.ui.foundation.VerticalScroller
import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
import androidx.ui.material.MaterialTheme
import androidx.ui.material.surface.Surface
import androidx.ui.test.ComposeTestCase
@@ -71,7 +71,7 @@
Row(ExpandedWidth) {
repeat(6) {
WithDensity {
- FlexColumn(crossAxisAlignment = CrossAxisAlignment.Start) {
+ FlexColumn {
val color = +memo {
val red = Random.nextInt(256)
val green = Random.nextInt(256)
@@ -88,15 +88,17 @@
text = "Some title",
style = TextStyle(Color.Black, 60.px.toSp())
)
- Row(
- ExpandedWidth,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- Text("3.5 ★", style = TextStyle(fontSize = 40.px.toSp()))
+ Row(ExpandedWidth) {
+ Text(
+ "3.5 ★",
+ style = TextStyle(fontSize = 40.px.toSp()),
+ modifier = Gravity.Center
+ )
ColoredRect(
width = 40.px.toDp(),
height = 40.px.toDp(),
- color = playStoreColor
+ color = playStoreColor,
+ modifier = Gravity.Center
)
}
}
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt
index 21e32e8..de1288b 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt
@@ -26,7 +26,6 @@
import androidx.ui.graphics.Color
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.foundation.ScrollerPosition
import androidx.ui.foundation.VerticalScroller
import androidx.ui.graphics.Paint
@@ -46,10 +45,7 @@
VerticalScroller(
scrollerPosition = scrollerPosition
) {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(ExpandedHeight) {
for (green in 0..0xFF) {
ColorStripe(0xFF, green, 0)
}
diff --git a/ui/settings.gradle b/ui/settings.gradle
index 3a37022..b777fc1 100644
--- a/ui/settings.gradle
+++ b/ui/settings.gradle
@@ -1,3 +1,11 @@
+pluginManagement {
+ repositories {
+ maven {
+ url = new File(buildscript.sourceFile.parent + "/../../../prebuilts/androidx/external").getCanonicalFile()
+ }
+ }
+}
+
// Calling includeProject(name, filePath) is shorthand for:
//
// include(name)
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt
index 8e0dd99..ce87853 100644
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt
@@ -26,11 +26,11 @@
import androidx.text.style.BaselineShiftSpan
import androidx.text.style.SkewXSpan
import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.spy
import org.mockito.stubbing.Answer
@@ -67,12 +67,12 @@
// first baselineShiftSpan is applied
var expectShift = (-fontSize * spanOutterMult).toInt()
doAnswer(updatePaintAnswer(baselineShift = expectShift))
- .`when`(spanOutter).updateMeasureState(ArgumentMatchers.any())
+ .`when`(spanOutter).updateMeasureState(any())
// second baselineShiftSpan is applied
expectShift = (-fontSize * (spanOutterMult + spanInnerMult)).toInt()
doAnswer(updatePaintAnswer(baselineShift = expectShift))
- .`when`(spanInner).updateMeasureState(ArgumentMatchers.any())
+ .`when`(spanInner).updateMeasureState(any())
val paint = simplePaint(fontSize.toFloat())
TextLayout(
@@ -98,12 +98,12 @@
// first baselineShiftSpan is applied
var expectShift = (-fontSize * spanOutterMult).toInt()
doAnswer(updatePaintAnswer(baselineShift = expectShift))
- .`when`(spanOutter).updateDrawState(ArgumentMatchers.any())
+ .`when`(spanOutter).updateDrawState(any())
// second baselineShiftSpan is applied
expectShift = (-fontSize * (spanOutterMult + spanInnerMult)).toInt()
doAnswer(updatePaintAnswer(baselineShift = expectShift))
- .`when`(spanInner).updateDrawState(ArgumentMatchers.any())
+ .`when`(spanInner).updateDrawState(any())
val paint = simplePaint(fontSize.toFloat())
TextLayout(
@@ -126,9 +126,9 @@
text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
doAnswer(updatePaintAnswer(skewX = skewXOutter))
- .`when`(spanOutter).updateDrawState(ArgumentMatchers.any())
+ .`when`(spanOutter).updateDrawState(any())
doAnswer(updatePaintAnswer(skewX = skewXInner + skewXOutter))
- .`when`(spanInner).updateDrawState(ArgumentMatchers.any())
+ .`when`(spanInner).updateDrawState(any())
TextLayout(
text,
@@ -150,9 +150,9 @@
text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
doAnswer(updatePaintAnswer(skewX = skewXOutter))
- .`when`(spanOutter).updateMeasureState(ArgumentMatchers.any())
+ .`when`(spanOutter).updateMeasureState(any())
doAnswer(updatePaintAnswer(skewX = skewXInner + skewXOutter))
- .`when`(spanInner).updateMeasureState(ArgumentMatchers.any())
+ .`when`(spanInner).updateMeasureState(any())
TextLayout(
text,
@@ -174,9 +174,9 @@
text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
doAnswer(updatePaintAnswer(scaleX = scaleXOutter))
- .`when`(spanOutter).updateDrawState(ArgumentMatchers.any())
+ .`when`(spanOutter).updateDrawState(any())
doAnswer(updatePaintAnswer(scaleX = scaleXInner * scaleXOutter))
- .`when`(spanInner).updateDrawState(ArgumentMatchers.any())
+ .`when`(spanInner).updateDrawState(any())
TextLayout(
text,
@@ -198,9 +198,9 @@
text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
doAnswer(updatePaintAnswer(scaleX = scaleXOutter))
- .`when`(spanOutter).updateMeasureState(ArgumentMatchers.any())
+ .`when`(spanOutter).updateMeasureState(any())
doAnswer(updatePaintAnswer(scaleX = scaleXInner * scaleXOutter))
- .`when`(spanInner).updateMeasureState(ArgumentMatchers.any())
+ .`when`(spanInner).updateMeasureState(any())
TextLayout(
text,
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.java
deleted file mode 100644
index ff4e53c..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class BaselineShiftSpanTest {
- @Test
- public void updateMeasureState_changePaintBaselineShift() {
- final float multiplier = 2.0f;
- final BaselineShiftSpan span = new BaselineShiftSpan(multiplier);
- final TextPaint textPaint = new TextPaint();
- // Make sure baseline shift is zero when created
- assertThat(textPaint.baselineShift).isEqualTo(0);
-
- span.updateMeasureState(textPaint);
- assertThat(textPaint.baselineShift).isNotEqualTo(0);
- }
-
- @Test
- public void updateDrawState_changePaintBaselineShift() {
- final float multiplier = 2.0f;
- final BaselineShiftSpan span = new BaselineShiftSpan(multiplier);
- final TextPaint textPaint = new TextPaint();
- // Make sure baseline shift is zero when created
- assertThat(textPaint.baselineShift).isEqualTo(0);
-
- span.updateDrawState(textPaint);
- assertThat(textPaint.baselineShift).isNotEqualTo(0);
- }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.kt
new file mode 100644
index 0000000..62cbcb3
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class BaselineShiftSpanTest {
+ @Test
+ fun updateMeasureState_changePaintBaselineShift() {
+ val multiplier = 2.0f
+ val span = BaselineShiftSpan(multiplier)
+ val textPaint = TextPaint()
+ // Make sure baseline shift is zero when created
+ assertThat(textPaint.baselineShift).isEqualTo(0)
+
+ span.updateMeasureState(textPaint)
+ assertThat(textPaint.baselineShift).isNotEqualTo(0)
+ }
+
+ @Test
+ fun updateDrawState_changePaintBaselineShift() {
+ val multiplier = 2.0f
+ val span = BaselineShiftSpan(multiplier)
+ val textPaint = TextPaint()
+ // Make sure baseline shift is zero when created
+ assertThat(textPaint.baselineShift).isEqualTo(0)
+
+ span.updateDrawState(textPaint)
+ assertThat(textPaint.baselineShift).isNotEqualTo(0)
+ }
+}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.java
deleted file mode 100644
index c843f3f..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class FontFeatureSpanTest {
- @Test(expected = NullPointerException.class)
- public void constructor_withNull_throwsException() {
- new FontFeatureSpan(null);
- }
-
- @Test
- public void updateMeasureState_changePaintFontFeatureSettings() {
- final String fontFeatureSettings = "\"kern\" 0";
- final FontFeatureSpan span = new FontFeatureSpan(fontFeatureSettings);
- final TextPaint textPaint = new TextPaint();
- // Make sure baseline shift is zero when created
- assertThat(textPaint.getFontFeatureSettings()).isNull();
-
- span.updateMeasureState(textPaint);
- assertThat(textPaint.getFontFeatureSettings()).isEqualTo(fontFeatureSettings);
- }
-
- @Test
- public void updateDrawState_changePaintBaselineShift() {
- final String fontFeatureSettings = "\"kern\" 0";
- final FontFeatureSpan span = new FontFeatureSpan(fontFeatureSettings);
- final TextPaint textPaint = new TextPaint();
- // Make sure baseline shift is zero when created
- assertThat(textPaint.getFontFeatureSettings()).isNull();
-
- span.updateDrawState(textPaint);
- assertThat(textPaint.getFontFeatureSettings()).isEqualTo(fontFeatureSettings);
- }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.kt
new file mode 100644
index 0000000..389c7f6
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class FontFeatureSpanTest {
+ @Test
+ fun updateMeasureState_changePaintFontFeatureSettings() {
+ val fontFeatureSettings = "\"kern\" 0"
+ val span = FontFeatureSpan(fontFeatureSettings)
+ val textPaint = TextPaint()
+ // Make sure baseline shift is zero when created
+ Truth.assertThat(textPaint.fontFeatureSettings).isNull()
+ span.updateMeasureState(textPaint)
+ Truth.assertThat(textPaint.fontFeatureSettings).isEqualTo(fontFeatureSettings)
+ }
+
+ @Test
+ fun updateDrawState_changePaintBaselineShift() {
+ val fontFeatureSettings = "\"kern\" 0"
+ val span = FontFeatureSpan(fontFeatureSettings)
+ val textPaint = TextPaint()
+ // Make sure baseline shift is zero when created
+ Truth.assertThat(textPaint.fontFeatureSettings).isNull()
+ span.updateDrawState(textPaint)
+ Truth.assertThat(textPaint.fontFeatureSettings).isEqualTo(fontFeatureSettings)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.java
deleted file mode 100644
index 774bdfc..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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.text.style;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class LetterSpacingSpanTest {
- @Test
- public void updateDrawState_changePaintLetterSpacing() {
- final float letterSpacing = 5.0f;
- final LetterSpacingSpan span = new LetterSpacingSpan(letterSpacing);
- final TextPaint paint = new TextPaint();
-
- span.updateDrawState(paint);
- assertThat(paint.getLetterSpacing()).isEqualTo(letterSpacing);
- }
-
- @Test
- public void updateMeasureState_changePaintLetterSpacing() {
- final float letterSpacing = 5.0f;
- final LetterSpacingSpan span = new LetterSpacingSpan(letterSpacing);
- final TextPaint paint = new TextPaint();
-
- span.updateMeasureState(paint);
- assertThat(paint.getLetterSpacing()).isEqualTo(letterSpacing);
- }
-
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.kt
new file mode 100644
index 0000000..09ebd6a
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class LetterSpacingSpanTest {
+ @Test
+ fun updateDrawState_changePaintLetterSpacing() {
+ val letterSpacing = 5.0f
+ val span = LetterSpacingSpan(letterSpacing)
+ val paint = TextPaint()
+ span.updateDrawState(paint)
+ Truth.assertThat(paint.letterSpacing).isEqualTo(letterSpacing)
+ }
+
+ @Test
+ fun updateMeasureState_changePaintLetterSpacing() {
+ val letterSpacing = 5.0f
+ val span = LetterSpacingSpan(letterSpacing)
+ val paint = TextPaint()
+ span.updateMeasureState(paint)
+ Truth.assertThat(paint.letterSpacing).isEqualTo(letterSpacing)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.java
deleted file mode 100644
index 56b79ca..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class ShadowSpanTest {
- @Test
- public void updateDrawStateTest() {
- final int color = 0xFF00FF00;
- final float offsetX = 1f;
- final float offsetY = 2f;
- final float radius = 3f;
- final ShadowSpan shadowSpan = new ShadowSpan(color, offsetX, offsetY, radius);
-
- final TextPaint textPaint = mock(TextPaint.class);
- shadowSpan.updateDrawState(textPaint);
- verify(textPaint, times(1)).setShadowLayer(radius, offsetX, offsetY, color);
- }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.kt
new file mode 100644
index 0000000..55222ac
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito
+
+@RunWith(JUnit4::class)
+@SmallTest
+class ShadowSpanTest {
+ @Test
+ fun updateDrawStateTest() {
+ val color = -0xff0100
+ val offsetX = 1f
+ val offsetY = 2f
+ val radius = 3f
+ val shadowSpan = ShadowSpan(color, offsetX, offsetY, radius)
+ val textPaint = Mockito.mock(TextPaint::class.java)
+ shadowSpan.updateDrawState(textPaint)
+ Mockito.verify(textPaint, Mockito.times(1))
+ .setShadowLayer(radius, offsetX, offsetY, color)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.java
deleted file mode 100644
index 6de9ab9..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class SkewXSpanTest {
- @Test
- public void updateMeasureState_changePaintTextSkewX() {
- final float skewX = 0.5f;
- final SkewXSpan span = new SkewXSpan(skewX);
- final TextPaint paint = new TextPaint();
-
- assertThat(span.getSkewX()).isEqualTo(skewX);
- span.updateMeasureState(paint);
- assertThat(paint.getTextSkewX()).isEqualTo(skewX);
- }
-
- @Test
- public void updateDrawState_changePaintTextSkewX() {
- final float skewX = 0.5f;
- final SkewXSpan span = new SkewXSpan(skewX);
- final TextPaint paint = new TextPaint();
-
- span.updateDrawState(paint);
- assertThat(paint.getTextSkewX()).isEqualTo(skewX);
- }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.kt
new file mode 100644
index 0000000..a134467
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class SkewXSpanTest {
+ @Test
+ fun updateMeasureState_changePaintTextSkewX() {
+ val skewX = 0.5f
+ val span = SkewXSpan(skewX)
+ val paint = TextPaint()
+ Truth.assertThat(span.skewX).isEqualTo(skewX)
+ span.updateMeasureState(paint)
+ Truth.assertThat(paint.textSkewX).isEqualTo(skewX)
+ }
+
+ @Test
+ fun updateDrawState_changePaintTextSkewX() {
+ val skewX = 0.5f
+ val span = SkewXSpan(skewX)
+ val paint = TextPaint()
+ span.updateDrawState(paint)
+ Truth.assertThat(paint.textSkewX).isEqualTo(skewX)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.java
deleted file mode 100644
index 9ed453e..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018 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.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-
-import android.graphics.Typeface;
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class TypefaceSpanTest {
- @Test
- public void updateDrawState_changesTypeface() {
- final Typeface typeface = mock(Typeface.class);
- final TypefaceSpan span = new TypefaceSpan(typeface);
- final TextPaint paint = new TextPaint();
-
- span.updateDrawState(paint);
-
- assertThat(paint.getTypeface()).isSameInstanceAs(typeface);
- }
-
- @Test
- public void updateMeasureState_changesTypeface() {
- final Typeface typeface = mock(Typeface.class);
- final TypefaceSpan span = new TypefaceSpan(typeface);
- final TextPaint paint = new TextPaint();
-
- span.updateMeasureState(paint);
-
- assertThat(paint.getTypeface()).isSameInstanceAs(typeface);
- }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.kt
new file mode 100644
index 0000000..74adc0ea
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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.text.style
+
+import android.graphics.Typeface
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito
+
+@RunWith(JUnit4::class)
+@SmallTest
+class TypefaceSpanTest {
+ @Test
+ fun updateDrawState_changesTypeface() {
+ val typeface = Mockito.mock(Typeface::class.java)
+ val span = TypefaceSpan(typeface)
+ val paint = TextPaint()
+ span.updateDrawState(paint)
+ Truth.assertThat(paint.typeface).isSameInstanceAs(typeface)
+ }
+
+ @Test
+ fun updateMeasureState_changesTypeface() {
+ val typeface = Mockito.mock(Typeface::class.java)
+ val span = TypefaceSpan(typeface)
+ val paint = TextPaint()
+ span.updateMeasureState(paint)
+ Truth.assertThat(paint.typeface).isSameInstanceAs(typeface)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.java
deleted file mode 100644
index beb22ef..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * Span which shifts the vertical position of baseline.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class BaselineShiftSpan extends MetricAffectingSpan {
- private final float mMultiplier;
-
- /**
- * Create a {@link BaselineShiftSpan}.
- * @param multiplier shift the baseline above by (baseline - ascent) * multiplier pixels.
- */
- public BaselineShiftSpan(float multiplier) {
- mMultiplier = multiplier;
- }
-
- @Override
- public void updateMeasureState(@NonNull TextPaint textPaint) {
- textPaint.baselineShift += (int)(textPaint.ascent() * mMultiplier);
- }
-
- @Override
- public void updateDrawState(@NonNull TextPaint textPaint) {
- textPaint.baselineShift += (int)(textPaint.ascent() * mMultiplier);
- }
-
- public float getMultiplier() {
- return mMultiplier;
- }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.kt
new file mode 100644
index 0000000..7e0c7be
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 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.text.style
+
+import kotlin.math.ceil
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span which shifts the vertical position of baseline.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+open class BaselineShiftSpan(val multiplier: Float) : MetricAffectingSpan() {
+
+ override fun updateMeasureState(textPaint: TextPaint) {
+ textPaint.baselineShift += ceil(textPaint.ascent() * multiplier).toInt()
+ }
+
+ override fun updateDrawState(textPaint: TextPaint) {
+ textPaint.baselineShift += ceil(textPaint.ascent() * multiplier).toInt()
+ }
+}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.java
deleted file mode 100644
index fa94f3e..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.text.Preconditions;
-
-/**
- * Span that change font feature settings for font.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class FontFeatureSpan extends MetricAffectingSpan {
- private final String mFontFeatureSettings;
- public FontFeatureSpan(@NonNull String fontFeatureSettings) {
- mFontFeatureSettings = Preconditions.checkNotNull(fontFeatureSettings);
- }
-
- @Override
- public void updateMeasureState(@NonNull TextPaint textPaint) {
- textPaint.setFontFeatureSettings(mFontFeatureSettings);
- }
-
- @Override
- public void updateDrawState(TextPaint textPaint) {
- textPaint.setFontFeatureSettings(mFontFeatureSettings);
- }
-
- /**
- * @return a font feature setting string this span specifies.
- */
- public String getFontFeatureSettings() {
- return mFontFeatureSettings;
- }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.kt
new file mode 100644
index 0000000..f35ca59
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span that change font feature settings for font.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class FontFeatureSpan(val fontFeatureSettings: String) : MetricAffectingSpan() {
+ override fun updateMeasureState(textPaint: TextPaint) {
+ textPaint.fontFeatureSettings = fontFeatureSettings
+ }
+
+ override fun updateDrawState(textPaint: TextPaint) {
+ textPaint.fontFeatureSettings = fontFeatureSettings
+ }
+}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.java
deleted file mode 100644
index 48f5585..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-// TODO(haoyuchang): Should support passing pixel when framework is ready.
-/**
- * Span used to adjust the letter spacing.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class LetterSpacingSpan extends MetricAffectingSpan {
- private final float mLetterSpacing;
-
- /**
- * Constructor of LetterSpacingSpan.
- *
- * @param letterSpacing the extra letter spacing in the unit of EM
- */
- public LetterSpacingSpan(float letterSpacing) {
- mLetterSpacing = letterSpacing;
- }
-
- @Override
- public void updateDrawState(@NonNull TextPaint textPaint) {
- textPaint.setLetterSpacing(mLetterSpacing);
- }
-
- @Override
- public void updateMeasureState(@NonNull TextPaint textPaint) {
- textPaint.setLetterSpacing(mLetterSpacing);
- }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.kt
new file mode 100644
index 0000000..30520b2
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 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.text.style
+
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+// TODO(haoyuchang): Should support passing pixel when framework is ready.
+/**
+ * Span used to adjust the letter spacing.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class LetterSpacingSpan(val letterSpacing: Float) : MetricAffectingSpan() {
+ override fun updateDrawState(textPaint: TextPaint) {
+ textPaint.letterSpacing = letterSpacing
+ }
+
+ override fun updateMeasureState(textPaint: TextPaint) {
+ textPaint.letterSpacing = letterSpacing
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.java
deleted file mode 100644
index 837e61a..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.graphics.Paint;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Px;
-import androidx.annotation.RestrictTo;
-
-/**
- * The span which modifies the height of the covered paragraphs. A paragraph is defined as a
- * segment of string divided by '\n' character. To make sure the span work as expected, the
- * boundary of this span should align with paragraph boundary.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class LineHeightSpan implements android.text.style.LineHeightSpan {
-
- @Px
- private final int mLineHeight;
-
- /**
- * Create a LineHeightSpan which sets the line height to <code>height</code> physical pixels.
- * @param lineHeight The specified line height in pixel unit, which is the space between the
- * baseline of adjacent lines.
- */
- public LineHeightSpan(@Px int lineHeight) {
- mLineHeight = lineHeight;
- }
-
- @Override
- public void chooseHeight(@NonNull CharSequence text, int start, int end, int spanstartv,
- int lineHeight, @NonNull Paint.FontMetricsInt fontMetricsInt) {
-
- // In StaticLayout, line height is computed with descent - ascent
- final int currentHeight = fontMetricsInt.descent - fontMetricsInt.ascent;
- // If current height is not positive, do nothing.
- if (currentHeight <= 0) {
- return;
- }
- final float ratio = mLineHeight * 1.0f / currentHeight;
- fontMetricsInt.descent = (int) Math.ceil(fontMetricsInt.descent * ratio);
- fontMetricsInt.ascent = fontMetricsInt.descent - mLineHeight;
- }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.kt
new file mode 100644
index 0000000..e3c1c7a
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.graphics.Paint.FontMetricsInt
+import androidx.annotation.RestrictTo
+
+/**
+ * The span which modifies the height of the covered paragraphs. A paragraph is defined as a
+ * segment of string divided by '\n' character. To make sure the span work as expected, the
+ * boundary of this span should align with paragraph boundary.
+ * @constructor Create a LineHeightSpan which sets the line height to `height` physical pixels.
+ * @param lineHeight The specified line height in pixel unit, which is the space between the
+ * baseline of adjacent lines.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class LineHeightSpan(val lineHeight: Int) : android.text.style.LineHeightSpan {
+ override fun chooseHeight(
+ text: CharSequence,
+ start: Int,
+ end: Int,
+ spanstartVertical: Int,
+ lineHeight: Int,
+ fontMetricsInt: FontMetricsInt
+ ) { // In StaticLayout, line height is computed with descent - ascent
+ val currentHeight = fontMetricsInt.descent - fontMetricsInt.ascent
+ // If current height is not positive, do nothing.
+ if (currentHeight <= 0) {
+ return
+ }
+ val ratio = this.lineHeight * 1.0f / currentHeight
+ fontMetricsInt.descent =
+ Math.ceil(fontMetricsInt.descent * ratio.toDouble()).toInt()
+ fontMetricsInt.ascent = fontMetricsInt.descent - this.lineHeight
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.java
deleted file mode 100644
index 19dfa7a..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.CharacterStyle;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * A span which applies a shadow effect to the covered text.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class ShadowSpan extends CharacterStyle {
- private final int mColor;
- private final float mOffsetX;
- private final float mOffsetY;
- private final float mRadius;
-
- public ShadowSpan(@ColorInt int color, float offsetX, float offsetY, float radius) {
- mColor = color;
- mOffsetX = offsetX;
- mOffsetY = offsetY;
- mRadius = radius;
- }
-
- @Override
- public void updateDrawState(@NonNull TextPaint tp) {
- tp.setShadowLayer(mRadius, mOffsetX, mOffsetY, mColor);
- }
-
- public int getColor() {
- return mColor;
- }
-
- public float getOffsetX() {
- return mOffsetX;
- }
-
- public float getOffsetY() {
- return mOffsetY;
- }
-
- public float getRadius() {
- return mRadius;
- }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.kt
new file mode 100644
index 0000000..b046c9d
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.text.TextPaint
+import android.text.style.CharacterStyle
+import androidx.annotation.RestrictTo
+
+/**
+ * A span which applies a shadow effect to the covered text.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class ShadowSpan(
+ val color: Int,
+ val offsetX: Float,
+ val offsetY: Float,
+ val radius: Float
+) : CharacterStyle() {
+ override fun updateDrawState(tp: TextPaint) {
+ tp.setShadowLayer(radius, offsetX, offsetY, color)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.java
deleted file mode 100644
index acacda1..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2019 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.RestrictTo;
-
-/**
- * Span which shear text in x direction. A pixel at (x, y) will be transfer to (x + y * skewX, y),
- * where y is the distant above baseline.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class SkewXSpan extends MetricAffectingSpan {
- private final float mSkewX;
-
- public SkewXSpan(float skewX) {
- mSkewX = skewX;
- }
-
- /**
- * @return the skew factor specified by this span.
- */
- public float getSkewX() {
- return mSkewX;
- }
-
- @Override
- public void updateDrawState(TextPaint textPaint) {
- textPaint.setTextSkewX(mSkewX + textPaint.getTextSkewX());
- }
-
- @Override
- public void updateMeasureState(TextPaint textPaint) {
- textPaint.setTextSkewX(mSkewX + textPaint.getTextSkewX());
- }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.kt
new file mode 100644
index 0000000..5755446
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.text.style
+
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span which shear text in x direction. A pixel at (x, y) will be transfer to (x + y * skewX, y),
+ * where y is the distant above baseline.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+open class SkewXSpan(val skewX: Float) : MetricAffectingSpan() {
+ override fun updateDrawState(textPaint: TextPaint) {
+ textPaint.textSkewX = skewX + textPaint.textSkewX
+ }
+
+ override fun updateMeasureState(textPaint: TextPaint) {
+ textPaint.textSkewX = skewX + textPaint.textSkewX
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.java
deleted file mode 100644
index 792c8b0..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2018 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * Span that displays text in the given Typeface. In Android Framework, TypefaceSpan that accepts
- * a Typeface as constructor argument was added in API 28, therefore was not usable before 28.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class TypefaceSpan extends MetricAffectingSpan {
-
- @NonNull
- private final Typeface mTypeface;
-
- /**
- * Constructs a {@link android.text.style.TypefaceSpan} from a {@link Typeface}. The previous
- * style of the TextPaint is overridden and the style of the typeface is used.
- *
- * @param typeface Typeface to render the text with
- */
- public TypefaceSpan(@NonNull Typeface typeface) {
- mTypeface = typeface;
- }
-
- /**
- * Returns the typeface set in the span.
- *
- * @return the typeface set
- * @see #TypefaceSpan(Typeface)
- */
- @NonNull
- public Typeface getTypeface() {
- return mTypeface;
- }
-
- @Override
- public void updateDrawState(@NonNull TextPaint ds) {
- updateTypeface(ds);
- }
-
- @Override
- public void updateMeasureState(@NonNull TextPaint paint) {
- updateTypeface(paint);
- }
-
- private void updateTypeface(@NonNull Paint paint) {
- if (mTypeface != null) {
- paint.setTypeface(mTypeface);
- }
- }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.kt
new file mode 100644
index 0000000..7e71a96
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 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.text.style
+
+import android.graphics.Paint
+import android.graphics.Typeface
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span that displays text in the given Typeface. In Android Framework, TypefaceSpan that accepts
+ * a Typeface as constructor argument was added in API 28, therefore was not usable before 28.
+ *
+ * @constructor Constructs a [android.text.style.TypefaceSpan] from a [Typeface]. The previous
+ * style of the TextPaint is overridden and the style of the typeface is used.
+ * @param typeface Typeface to render the text with.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class TypefaceSpan(val typeface: Typeface) : MetricAffectingSpan() {
+ override fun updateDrawState(ds: TextPaint) {
+ updateTypeface(ds)
+ }
+
+ override fun updateMeasureState(paint: TextPaint) {
+ updateTypeface(paint)
+ }
+
+ private fun updateTypeface(paint: Paint) {
+ paint.typeface = typeface
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-core/api/0.1.0-dev03.txt b/ui/ui-core/api/0.1.0-dev03.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/0.1.0-dev03.txt
+++ b/ui/ui-core/api/0.1.0-dev03.txt
@@ -1454,6 +1454,14 @@
enum_constant public static final androidx.ui.graphics.FilterQuality none;
}
+ public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+ ctor public FixedScale(float value);
+ method public float component1();
+ method public androidx.ui.graphics.FixedScale copy(float value);
+ method public float getValue();
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ }
+
public interface Image {
method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
}
+ public interface ScaleFit {
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+ }
+
+ public static final class ScaleFit.Companion {
+ method public androidx.ui.graphics.ScaleFit getFillHeight();
+ method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+ method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+ method public androidx.ui.graphics.ScaleFit getFillWidth();
+ method public androidx.ui.graphics.ScaleFit getFit();
+ method public androidx.ui.graphics.FixedScale getNone();
+ property public final androidx.ui.graphics.ScaleFit FillHeight;
+ property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+ property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+ property public final androidx.ui.graphics.ScaleFit FillWidth;
+ property public final androidx.ui.graphics.ScaleFit Fit;
+ property public final androidx.ui.graphics.FixedScale None;
+ }
+
+ public final class ScaleFitKt {
+ ctor public ScaleFitKt();
+ }
+
public final class Shader {
ctor public Shader(android.graphics.Shader nativeShader);
method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/api_lint.ignore b/ui/ui-core/api/api_lint.ignore
index 9024498..cdb5983 100644
--- a/ui/ui-core/api/api_lint.ignore
+++ b/ui/ui-core/api/api_lint.ignore
@@ -205,10 +205,16 @@
Missing nullability on field `Companion` in class `class androidx.ui.engine.geometry.Size`
MissingNullability: androidx.ui.graphics.Color#Companion:
Missing nullability on field `Companion` in class `class androidx.ui.graphics.Color`
+MissingNullability: androidx.ui.graphics.FixedScale#equals(Object) parameter #0:
+ Missing nullability on parameter `p` in method `equals`
+MissingNullability: androidx.ui.graphics.FixedScale#toString():
+ Missing nullability on method `toString` return
MissingNullability: androidx.ui.graphics.MaskFilter#Companion:
Missing nullability on field `Companion` in class `class androidx.ui.graphics.MaskFilter`
MissingNullability: androidx.ui.graphics.Path#Companion:
Missing nullability on field `Companion` in class `class androidx.ui.graphics.Path`
+MissingNullability: androidx.ui.graphics.ScaleFit#Companion:
+ Missing nullability on field `Companion` in class `class androidx.ui.graphics.ScaleFit`
MissingNullability: androidx.ui.graphics.colorspace.ColorSpaces#INSTANCE:
Missing nullability on field `INSTANCE` in class `class androidx.ui.graphics.colorspace.ColorSpaces`
MissingNullability: androidx.ui.graphics.colorspace.Illuminant#INSTANCE:
diff --git a/ui/ui-core/api/current.txt b/ui/ui-core/api/current.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/current.txt
+++ b/ui/ui-core/api/current.txt
@@ -1454,6 +1454,14 @@
enum_constant public static final androidx.ui.graphics.FilterQuality none;
}
+ public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+ ctor public FixedScale(float value);
+ method public float component1();
+ method public androidx.ui.graphics.FixedScale copy(float value);
+ method public float getValue();
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ }
+
public interface Image {
method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
}
+ public interface ScaleFit {
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+ }
+
+ public static final class ScaleFit.Companion {
+ method public androidx.ui.graphics.ScaleFit getFillHeight();
+ method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+ method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+ method public androidx.ui.graphics.ScaleFit getFillWidth();
+ method public androidx.ui.graphics.ScaleFit getFit();
+ method public androidx.ui.graphics.FixedScale getNone();
+ property public final androidx.ui.graphics.ScaleFit FillHeight;
+ property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+ property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+ property public final androidx.ui.graphics.ScaleFit FillWidth;
+ property public final androidx.ui.graphics.ScaleFit Fit;
+ property public final androidx.ui.graphics.FixedScale None;
+ }
+
+ public final class ScaleFitKt {
+ ctor public ScaleFitKt();
+ }
+
public final class Shader {
ctor public Shader(android.graphics.Shader nativeShader);
method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt
@@ -1454,6 +1454,14 @@
enum_constant public static final androidx.ui.graphics.FilterQuality none;
}
+ public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+ ctor public FixedScale(float value);
+ method public float component1();
+ method public androidx.ui.graphics.FixedScale copy(float value);
+ method public float getValue();
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ }
+
public interface Image {
method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
}
+ public interface ScaleFit {
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+ }
+
+ public static final class ScaleFit.Companion {
+ method public androidx.ui.graphics.ScaleFit getFillHeight();
+ method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+ method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+ method public androidx.ui.graphics.ScaleFit getFillWidth();
+ method public androidx.ui.graphics.ScaleFit getFit();
+ method public androidx.ui.graphics.FixedScale getNone();
+ property public final androidx.ui.graphics.ScaleFit FillHeight;
+ property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+ property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+ property public final androidx.ui.graphics.ScaleFit FillWidth;
+ property public final androidx.ui.graphics.ScaleFit Fit;
+ property public final androidx.ui.graphics.FixedScale None;
+ }
+
+ public final class ScaleFitKt {
+ ctor public ScaleFitKt();
+ }
+
public final class Shader {
ctor public Shader(android.graphics.Shader nativeShader);
method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/public_plus_experimental_current.txt b/ui/ui-core/api/public_plus_experimental_current.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/public_plus_experimental_current.txt
+++ b/ui/ui-core/api/public_plus_experimental_current.txt
@@ -1454,6 +1454,14 @@
enum_constant public static final androidx.ui.graphics.FilterQuality none;
}
+ public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+ ctor public FixedScale(float value);
+ method public float component1();
+ method public androidx.ui.graphics.FixedScale copy(float value);
+ method public float getValue();
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ }
+
public interface Image {
method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
}
+ public interface ScaleFit {
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+ }
+
+ public static final class ScaleFit.Companion {
+ method public androidx.ui.graphics.ScaleFit getFillHeight();
+ method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+ method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+ method public androidx.ui.graphics.ScaleFit getFillWidth();
+ method public androidx.ui.graphics.ScaleFit getFit();
+ method public androidx.ui.graphics.FixedScale getNone();
+ property public final androidx.ui.graphics.ScaleFit FillHeight;
+ property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+ property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+ property public final androidx.ui.graphics.ScaleFit FillWidth;
+ property public final androidx.ui.graphics.ScaleFit Fit;
+ property public final androidx.ui.graphics.FixedScale None;
+ }
+
+ public final class ScaleFitKt {
+ ctor public ScaleFitKt();
+ }
+
public final class Shader {
ctor public Shader(android.graphics.Shader nativeShader);
method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/restricted_0.1.0-dev03.txt b/ui/ui-core/api/restricted_0.1.0-dev03.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-core/api/restricted_0.1.0-dev03.txt
@@ -1454,6 +1454,14 @@
enum_constant public static final androidx.ui.graphics.FilterQuality none;
}
+ public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+ ctor public FixedScale(float value);
+ method public float component1();
+ method public androidx.ui.graphics.FixedScale copy(float value);
+ method public float getValue();
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ }
+
public interface Image {
method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
}
+ public interface ScaleFit {
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+ }
+
+ public static final class ScaleFit.Companion {
+ method public androidx.ui.graphics.ScaleFit getFillHeight();
+ method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+ method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+ method public androidx.ui.graphics.ScaleFit getFillWidth();
+ method public androidx.ui.graphics.ScaleFit getFit();
+ method public androidx.ui.graphics.FixedScale getNone();
+ property public final androidx.ui.graphics.ScaleFit FillHeight;
+ property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+ property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+ property public final androidx.ui.graphics.ScaleFit FillWidth;
+ property public final androidx.ui.graphics.ScaleFit Fit;
+ property public final androidx.ui.graphics.FixedScale None;
+ }
+
+ public final class ScaleFitKt {
+ ctor public ScaleFitKt();
+ }
+
public final class Shader {
ctor public Shader(android.graphics.Shader nativeShader);
method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/restricted_current.txt b/ui/ui-core/api/restricted_current.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/restricted_current.txt
+++ b/ui/ui-core/api/restricted_current.txt
@@ -1454,6 +1454,14 @@
enum_constant public static final androidx.ui.graphics.FilterQuality none;
}
+ public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+ ctor public FixedScale(float value);
+ method public float component1();
+ method public androidx.ui.graphics.FixedScale copy(float value);
+ method public float getValue();
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ }
+
public interface Image {
method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
}
+ public interface ScaleFit {
+ method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+ field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+ }
+
+ public static final class ScaleFit.Companion {
+ method public androidx.ui.graphics.ScaleFit getFillHeight();
+ method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+ method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+ method public androidx.ui.graphics.ScaleFit getFillWidth();
+ method public androidx.ui.graphics.ScaleFit getFit();
+ method public androidx.ui.graphics.FixedScale getNone();
+ property public final androidx.ui.graphics.ScaleFit FillHeight;
+ property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+ property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+ property public final androidx.ui.graphics.ScaleFit FillWidth;
+ property public final androidx.ui.graphics.ScaleFit Fit;
+ property public final androidx.ui.graphics.FixedScale None;
+ }
+
+ public final class ScaleFitKt {
+ ctor public ScaleFitKt();
+ }
+
public final class Shader {
ctor public Shader(android.graphics.Shader nativeShader);
method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/Em.kt b/ui/ui-core/src/main/java/androidx/ui/core/Em.kt
index 6a49013..fea4caf 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/Em.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/Em.kt
@@ -17,6 +17,10 @@
package androidx.ui.core
+import androidx.compose.Immutable
+import kotlin.math.max
+import kotlin.math.min
+
/**
* Dimension value representing Em. 1 Em is defined to be the font size when doing the text layout.
* For example:
@@ -35,6 +39,7 @@
* }
* }
*/
+@Immutable
data /*inline*/ class Em(val value: Float) {
/**
* Add two [Em]s together.
@@ -118,9 +123,9 @@
inline operator fun Int.times(other: Em) =
Em(this * other.value)
-inline fun min(a: Em, b: Em): Em = Em(value = kotlin.math.min(a.value, b.value))
+inline fun min(a: Em, b: Em): Em = Em(value = min(a.value, b.value))
-inline fun max(a: Em, b: Em): Em = Em(value = kotlin.math.max(a.value, b.value))
+inline fun max(a: Em, b: Em): Em = Em(value = max(a.value, b.value))
/**
* Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt b/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt
index ff853bd..6668aa7 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt
@@ -17,6 +17,10 @@
package androidx.ui.core
+import androidx.compose.Immutable
+import kotlin.math.max
+import kotlin.math.min
+
/**
* Dimension value representing scaled pixels (sp). Font related APIs specify their
* dimensions such as font size in SP with Sp objects. Sp are normally
@@ -30,6 +34,7 @@
* [toPx] is normally needed only for painting operations.
*/
@Suppress("EXPERIMENTAL_FEATURE_WARNING")
+@Immutable
data /*inline*/ class Sp(val value: Float) {
/**
* Add two [Sp]s together.
@@ -140,11 +145,11 @@
}
inline fun min(a: Sp, b: Sp): Sp = checkNotInherit(a, b) {
- Sp(value = kotlin.math.min(a.value, b.value))
+ Sp(value = min(a.value, b.value))
}
inline fun max(a: Sp, b: Sp): Sp = checkNotInherit(a, b) {
- Sp(value = kotlin.math.max(a.value, b.value))
+ Sp(value = max(a.value, b.value))
}
/**
diff --git a/ui/ui-core/src/main/java/androidx/ui/graphics/ScaleFit.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/ScaleFit.kt
new file mode 100644
index 0000000..a91c695
--- /dev/null
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/ScaleFit.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2019 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.ui.graphics
+
+import androidx.ui.core.PxSize
+
+private const val OriginalScale = 1.0f
+
+/**
+ * Represents a rule to apply to scale a source rectangle to be inscribed into a destination
+ */
+interface ScaleFit {
+
+ /**
+ * Computes the scale factor to apply to both dimensions in order to fit the source
+ * appropriately with the given destination size
+ */
+ fun scale(srcSize: PxSize, dstSize: PxSize): Float
+
+ /**
+ * Companion object containing commonly used [ScaleFit] implementations
+ */
+ companion object {
+
+ /**
+ * Scale the source maintaining the aspect ratio so that the bounds match the maximum of
+ * the destination width or height. This can cover a larger area than the destination.
+ */
+ val FillMaxDimension = object : ScaleFit {
+ override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+ computeFillMaxDimension(srcSize, dstSize)
+ }
+
+ /**
+ * Scale the source maintaining the aspect ratio so that the bounds match the minimum of
+ * the destination width or height. This will always fill an area smaller than or equal to
+ * the destination.
+ */
+ val FillMinDimension = object : ScaleFit {
+ override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+ computeFillMinDimension(srcSize, dstSize)
+ }
+
+ /**
+ * Scale the source maintaining the aspect ratio so that the bounds match the destination
+ * height. This can cover a larger area than the destination if the height is larger than
+ * the width.
+ */
+ val FillHeight = object : ScaleFit {
+ override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+ computeFillHeight(srcSize, dstSize)
+ }
+
+ /**
+ * Scale the source maintaining the aspect ratio so that the bounds match the
+ * destination width. This can cover a larger area than the destination if the width is
+ * larger than the height.
+ */
+ val FillWidth = object : ScaleFit {
+ override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+ computeFillWidth(srcSize, dstSize)
+ }
+
+ /**
+ * Scale the source to maintain the aspect ratio to fit within the destination bounds
+ * if the source is larger than the destination. If the source is smaller than or equal
+ * to the destination in both dimensions, this behaves similarly to [None]. This will
+ * always be contained within the bounds of the destination.
+ */
+ val Fit = object : ScaleFit {
+ override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+ if (srcSize.width <= dstSize.width && srcSize.height <= dstSize.height) {
+ OriginalScale
+ } else {
+ computeFillMinDimension(srcSize, dstSize)
+ }
+ }
+
+ /**
+ * Do not apply any scaling to the source
+ */
+ val None = FixedScale(OriginalScale)
+ }
+}
+
+/**
+ * [ScaleFit] implementation that always scales the dimension by the provided
+ * fixed floating point value
+ */
+data class FixedScale(val value: Float) : ScaleFit {
+ override fun scale(srcSize: PxSize, dstSize: PxSize): Float = value
+}
+
+private fun computeFillMaxDimension(srcSize: PxSize, dstSize: PxSize): Float =
+ if (dstSize.width > dstSize.height) {
+ computeFillWidth(srcSize, dstSize)
+ } else {
+ computeFillHeight(srcSize, dstSize)
+ }
+
+private fun computeFillMinDimension(srcSize: PxSize, dstSize: PxSize): Float =
+ if (dstSize.width < dstSize.height) {
+ computeFillWidth(srcSize, dstSize)
+ } else {
+ computeFillHeight(srcSize, dstSize)
+ }
+
+private fun computeFillWidth(srcSize: PxSize, dstSize: PxSize): Float =
+ dstSize.width.value / srcSize.width.value
+
+private fun computeFillHeight(srcSize: PxSize, dstSize: PxSize): Float =
+ dstSize.height.value / srcSize.height.value
diff --git a/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt
index 7f8cbc9..9b15e42 100644
--- a/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt
@@ -16,6 +16,7 @@
package androidx.ui.graphics
+import androidx.compose.Immutable
import androidx.ui.core.Px
import androidx.ui.core.lerp
import androidx.ui.core.px
@@ -24,6 +25,7 @@
/**
* A single shadow.
*/
+@Immutable
data class Shadow(
val color: Color = Color(0xFF000000),
val offset: Offset = Offset.zero,
diff --git a/ui/ui-core/src/test/java/androidx/ui/graphics/ScaleFitTest.kt b/ui/ui-core/src/test/java/androidx/ui/graphics/ScaleFitTest.kt
new file mode 100644
index 0000000..d33cc18
--- /dev/null
+++ b/ui/ui-core/src/test/java/androidx/ui/graphics/ScaleFitTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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.ui.graphics
+
+import androidx.test.filters.SmallTest
+import androidx.ui.core.IntPx
+import androidx.ui.core.PxSize
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class ScaleFitTest {
+
+ @Test
+ fun testScaleNone() {
+ val scale = ScaleFit.None.scale(
+ srcSize = PxSize(IntPx(100), IntPx(100)),
+ dstSize = PxSize(IntPx(200), IntPx(200))
+ )
+ assertEquals(1.0f, scale)
+ }
+
+ @Test
+ fun testScaleFit() {
+ val scale = ScaleFit.Fit.scale(
+ srcSize = PxSize(IntPx(200), IntPx(100)),
+ dstSize = PxSize(IntPx(100), IntPx(200))
+ )
+ assertEquals(.5f, scale)
+ }
+
+ @Test
+ fun testScaleFillWidth() {
+ val scale = ScaleFit.FillWidth.scale(
+ srcSize = PxSize(IntPx(400), IntPx(100)),
+ dstSize = PxSize(IntPx(100), IntPx(200))
+ )
+ assertEquals(0.25f, scale)
+ }
+
+ @Test
+ fun testScaleFillHeight() {
+ val scale = ScaleFit.FillHeight.scale(
+ srcSize = PxSize(IntPx(400), IntPx(100)),
+ dstSize = PxSize(IntPx(100), IntPx(200))
+ )
+ assertEquals(2.0f, scale)
+ }
+
+ @Test
+ fun testScaleFillMaxDimension() {
+ val scale = ScaleFit.FillMaxDimension.scale(
+ srcSize = PxSize(IntPx(400), IntPx(100)),
+ dstSize = PxSize(IntPx(100), IntPx(200))
+ )
+ assertEquals(2.0f, scale)
+ }
+
+ @Test
+ fun testScaleFillMinDimension() {
+ val scale = ScaleFit.FillMinDimension.scale(
+ srcSize = PxSize(IntPx(400), IntPx(100)),
+ dstSize = PxSize(IntPx(100), IntPx(200))
+ )
+ assertEquals(0.25f, scale)
+ }
+}
\ No newline at end of file
diff --git a/ui/ui-foundation/OWNERS b/ui/ui-foundation/OWNERS
index 40a5c8b..0a4bd6c 100644
--- a/ui/ui-foundation/OWNERS
+++ b/ui/ui-foundation/OWNERS
@@ -3,3 +3,4 @@
andreykulikov@google.com
malkov@google.com
lpf@google.com
+qqd@google.com
diff --git a/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt b/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt
index 84d0564..3a4dff7 100644
--- a/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt
+++ b/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt
@@ -24,6 +24,7 @@
import androidx.ui.core.Alignment
import androidx.ui.core.Dp
import androidx.ui.core.Draw
+import androidx.ui.core.Modifier
import androidx.ui.core.Text
import androidx.ui.core.TextField
import androidx.ui.core.dp
@@ -51,9 +52,10 @@
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.layout.Wrap
import androidx.ui.graphics.Paint
-import androidx.ui.layout.CrossAxisAlignment
+import androidx.ui.layout.ColumnScope
import androidx.ui.layout.ExpandedHeight
import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
import androidx.ui.text.ParagraphStyle
import androidx.ui.text.TextStyle
import androidx.ui.text.style.TextAlign
@@ -66,9 +68,9 @@
val exampleIndex = +state { 0 }
val totalExamples = 9
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+ Column {
FlexRow(
- ExpandedWidth,
+ ExpandedWidth wraps Gravity.Center,
mainAxisAlignment = MainAxisAlignment.SpaceBetween
) {
inflexible {
@@ -155,11 +157,11 @@
}
@Composable
-fun PopupToggle() {
+fun ColumnScope.PopupToggle() {
val showPopup = +state { true }
val containerSize = 100.dp
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+ Column(Gravity.Center) {
Container(width = containerSize, height = containerSize) {
if (showPopup.value) {
Popup(alignment = Alignment.Center) {
@@ -187,9 +189,8 @@
}
@Composable
-fun PopupWithChangingContent() {
- Container {
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupWithChangingContent() {
+ Column(Gravity.Center) {
val heightSize = 120.dp
val widthSize = 160.dp
val popupContentState = +state { 0 }
@@ -229,11 +230,10 @@
}
)
}
- }
}
@Composable
-fun PopupWithChangingParent() {
+fun ColumnScope.PopupWithChangingParent() {
val containerWidth = 400.dp
val containerHeight = 200.dp
val parentAlignment = +state { Alignment.TopLeft }
@@ -241,7 +241,7 @@
val parentHeight = +state { 60.dp }
val parentSizeChanged = +state { false }
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+ Column(Gravity.Center) {
Container(
height = containerHeight,
width = containerWidth,
@@ -290,9 +290,8 @@
}
@Composable
-fun PopupDropdownAlignment() {
- Container {
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupDropdownAlignment() {
+ Column(Gravity.Center) {
val heightSize = 120.dp
val widthSize = 160.dp
val dropDownAlignment = +state { DropDownAlignment.Left }
@@ -327,18 +326,17 @@
}
}
}
- }
}
@Composable
-fun PopupAlignmentDemo() {
- Container(alignment = Alignment.Center) {
+fun ColumnScope.PopupAlignmentDemo() {
+ Container(Gravity.Center) {
val heightSize = 200.dp
val widthSize = 400.dp
val counter = +state { 0 }
val popupAlignment = +state { Alignment.TopLeft }
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+ Column {
ColoredContainer(
height = heightSize,
width = widthSize,
@@ -368,7 +366,7 @@
}
HeightSpacer(10.dp)
- ColoredContainer(color = Color.White) {
+ ColoredContainer(color = Color.White, modifier = Gravity.Center) {
Text("Alignment: " + popupAlignment.value.toString())
}
}
@@ -376,9 +374,8 @@
}
@Composable
-fun PopupWithEditText() {
- Container {
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupWithEditText() {
+ Column(Gravity.Center) {
val widthSize = 190.dp
val heightSize = 120.dp
val editLineSize = 150.dp
@@ -393,7 +390,8 @@
ColoredContainer(
height = heightSize,
width = widthSize,
- color = Color.Red
+ color = Color.Red,
+ modifier = Gravity.Center
) {
if (showPopup.value) {
Popup(
@@ -419,13 +417,11 @@
}
}
}
- }
}
@Composable
-fun PopupWithChangingSize() {
- Container {
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupWithChangingSize() {
+ Column(Gravity.Center) {
val showPopup = +state { true }
val heightSize = 120.dp
val widthSize = 160.dp
@@ -473,21 +469,16 @@
}
)
}
- }
}
@Composable
-fun PopupInsideScroller() {
+fun ColumnScope.PopupInsideScroller() {
val heightSize = 400.dp
val widthSize = 200.dp
- Container(width = widthSize, height = heightSize) {
+ Container(width = widthSize, height = heightSize, modifier = Gravity.Center) {
VerticalScroller {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- ColoredContainer(
- width = 80.dp,
+ Column(ExpandedHeight) {
+ ColoredContainer(width = 80.dp,
height = 160.dp,
color = Color(0xFF00FF00)
) {
@@ -497,7 +488,7 @@
}
for (i in 0..30) {
- Text("Scroll #$i")
+ Text(text = "Scroll #$i", modifier = Gravity.Center)
}
}
}
@@ -506,40 +497,39 @@
@Composable
fun PopupOnKeyboardUp() {
- Container {
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
- val widthSize = 190.dp
- val heightSize = 120.dp
+ Column {
+ val widthSize = 190.dp
+ val heightSize = 120.dp
- HeightSpacer(350.dp)
- Text("Start typing in the EditText below the parent(Red rectangle)")
- ColoredContainer(
- height = heightSize,
- width = widthSize,
- color = Color.Red
- ) {
- Popup(Alignment.Center) {
- ColoredContainer(color = Color.Green) {
- Text("Popup")
- }
+ HeightSpacer(350.dp)
+ Text("Start typing in the EditText below the parent(Red rectangle)")
+ ColoredContainer(
+ height = heightSize,
+ width = widthSize,
+ color = Color.Red,
+ modifier = Gravity.Center
+ ) {
+ Popup(Alignment.Center) {
+ ColoredContainer(color = Color.Green) {
+ Text("Popup")
}
}
-
- EditLine(initialText = "Continue typing...", color = Color.Gray)
-
- HeightSpacer(24.dp)
}
+
+ EditLine(initialText = "Continue typing...", color = Color.Gray)
+
+ HeightSpacer(24.dp)
}
}
@Composable
-fun ClickableTextWithBackground(
+fun ColumnScope.ClickableTextWithBackground(
text: String,
color: Color,
onClick: (() -> Unit)? = null,
padding: EdgeInsets = EdgeInsets(0.dp)
) {
- Wrap {
+ Container(Gravity.Center) {
DrawShape(RectangleShape, color)
Clickable( {
Container(padding = padding) {
@@ -551,6 +541,7 @@
@Composable
fun ColoredContainer(
+ modifier: Modifier = Modifier.None,
width: Dp? = null,
height: Dp? = null,
color: Color,
@@ -560,6 +551,7 @@
children: @Composable() () -> Unit
) {
Container(
+ modifier = modifier,
width = width,
height = height,
alignment = alignment,
diff --git a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
index ece96a5..e03a0a4 100644
--- a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
+++ b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
@@ -42,7 +42,6 @@
import androidx.ui.layout.Column
import androidx.ui.layout.ConstrainedBox
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.DpConstraints
import androidx.ui.core.Text
import androidx.ui.core.dp
@@ -278,7 +277,7 @@
Align(alignment = Alignment.TopLeft) {
ConstrainedBox(constraints = constraints) {
VerticalScroller(scrollerPosition = scrollerPosition) {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
colors.forEach { color ->
Container(
height = 5.px.toDp(),
@@ -316,7 +315,7 @@
Align(alignment = Alignment.TopLeft) {
ConstrainedBox(constraints = constraints) {
HorizontalScroller(scrollerPosition = scrollerPosition) {
- Row(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Row {
colors.forEach { color ->
Container(
width = 5.px.toDp(),
diff --git a/ui/ui-framework/api/0.1.0-dev03.txt b/ui/ui-framework/api/0.1.0-dev03.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/0.1.0-dev03.txt
+++ b/ui/ui-framework/api/0.1.0-dev03.txt
@@ -145,7 +145,9 @@
method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
@@ -347,13 +349,13 @@
public final class VectorAssetKt {
ctor public VectorAssetKt();
- method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+ method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
}
public final class VectorComposeKt {
ctor public VectorComposeKt();
- method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
- method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
}
diff --git a/ui/ui-framework/api/current.txt b/ui/ui-framework/api/current.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/current.txt
+++ b/ui/ui-framework/api/current.txt
@@ -145,7 +145,9 @@
method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
@@ -347,13 +349,13 @@
public final class VectorAssetKt {
ctor public VectorAssetKt();
- method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+ method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
}
public final class VectorComposeKt {
ctor public VectorComposeKt();
- method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
- method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
}
diff --git a/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt
@@ -145,7 +145,9 @@
method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
@@ -347,13 +349,13 @@
public final class VectorAssetKt {
ctor public VectorAssetKt();
- method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+ method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
}
public final class VectorComposeKt {
ctor public VectorComposeKt();
- method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
- method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
}
diff --git a/ui/ui-framework/api/public_plus_experimental_current.txt b/ui/ui-framework/api/public_plus_experimental_current.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/public_plus_experimental_current.txt
+++ b/ui/ui-framework/api/public_plus_experimental_current.txt
@@ -145,7 +145,9 @@
method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
@@ -347,13 +349,13 @@
public final class VectorAssetKt {
ctor public VectorAssetKt();
- method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+ method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
}
public final class VectorComposeKt {
ctor public VectorComposeKt();
- method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
- method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
}
diff --git a/ui/ui-framework/api/restricted_0.1.0-dev03.txt b/ui/ui-framework/api/restricted_0.1.0-dev03.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-framework/api/restricted_0.1.0-dev03.txt
@@ -145,7 +145,9 @@
method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
@@ -347,13 +349,13 @@
public final class VectorAssetKt {
ctor public VectorAssetKt();
- method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+ method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
}
public final class VectorComposeKt {
ctor public VectorComposeKt();
- method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
- method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
}
diff --git a/ui/ui-framework/api/restricted_current.txt b/ui/ui-framework/api/restricted_current.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/restricted_current.txt
+++ b/ui/ui-framework/api/restricted_current.txt
@@ -145,7 +145,9 @@
method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+ method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
}
@@ -347,13 +349,13 @@
public final class VectorAssetKt {
ctor public VectorAssetKt();
- method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+ method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
}
public final class VectorComposeKt {
ctor public VectorComposeKt();
- method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
- method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+ method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
}
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt
index cb6aa17..634bfd1 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt
@@ -24,7 +24,6 @@
import androidx.ui.core.px
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.material.Button
import androidx.ui.material.MaterialTheme
@@ -33,6 +32,7 @@
import androidx.compose.unaryPlus
import androidx.ui.layout.ExpandedHeight
import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
/** A [SemanticProperty] is used to store semantic information about a component.
*
@@ -174,12 +174,13 @@
InvokeActionsByParameters(actions)
}
}
- Row(
- ExpandedWidth,
- mainAxisAlignment = MainAxisAlignment.Center,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- Container(height = 300.dp, width = 500.dp, children = children)
+ Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.Center) {
+ Container(
+ height = 300.dp,
+ width = 500.dp,
+ modifier = Gravity.Center,
+ children = children
+ )
}
}
}
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt
index 2b44e7b..5237a98 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt
@@ -28,6 +28,7 @@
import androidx.ui.graphics.Color
import androidx.ui.graphics.HorizontalGradient
import androidx.ui.graphics.RadialGradient
+import androidx.ui.graphics.ScaleFit
import androidx.ui.graphics.SolidColor
import androidx.ui.graphics.TileMode
import androidx.ui.graphics.VerticalGradient
@@ -52,10 +53,10 @@
val vectorAsset = +loadVectorResource(R.drawable.ic_crane)
WithDensity {
vectorAsset.resource.resource?.let {
- val width = it.defaultWidth.toDp()
- val height = it.defaultHeight.toDp()
- Container(width = width, height = height) {
- DrawVector(it)
+ Center {
+ Container(width = 200.dp, height = 100.dp) {
+ DrawVector(it)
+ }
}
}
}
@@ -76,7 +77,8 @@
DrawVector(
name = "vectorShape",
defaultWidth = width,
- defaultHeight = height
+ defaultHeight = height,
+ scaleFit = ScaleFit.FillMaxDimension
) { viewportWidth, viewportHeight ->
Group(
scaleX = 0.75f,
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt
index fd5be7d..29b8b46 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt
@@ -37,7 +37,6 @@
import androidx.ui.input.ImeAction
import androidx.ui.input.KeyboardType
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.HeightSpacer
import androidx.ui.material.MaterialTheme
@@ -47,7 +46,7 @@
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
val nameState = +state { "Enter name here" }
val emailState = +state { "Enter email here" }
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
index 5175929..500c1f6a 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
@@ -263,6 +263,8 @@
}
}
assertTrue(latch.await(1, TimeUnit.SECONDS))
+
+ assertCountDownOnlyWhileEnabled(enabled, model)
}
@Test
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt b/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt
index 7620cfd..763381f 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt
@@ -32,7 +32,6 @@
import androidx.ui.input.TextInputService
import androidx.ui.input.TransformedText
import androidx.ui.input.VisualTransformation
-import androidx.ui.input.identityOffsetMap
import androidx.ui.text.AnnotatedString
import androidx.ui.text.Paragraph
import androidx.ui.text.ParagraphConstraints
@@ -317,7 +316,7 @@
): TransformedText {
val annotatedString = AnnotatedString(value.text)
return visualTransformation?.filter(annotatedString)
- ?: TransformedText(annotatedString, identityOffsetMap)
+ ?: TransformedText(annotatedString, OffsetMap.identityOffsetMap)
}
/**
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
index fe2affe..2b5584d 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
@@ -20,7 +20,6 @@
import android.content.res.Configuration
import android.view.ViewGroup
import androidx.annotation.CheckResult
-import androidx.annotation.RestrictTo
import androidx.ui.core.input.FocusManager
import androidx.ui.input.TextInputService
import androidx.compose.Ambient
@@ -39,7 +38,6 @@
import androidx.compose.unaryPlus
import androidx.ui.autofill.Autofill
import androidx.ui.autofill.AutofillTree
-import androidx.ui.core.text.AndroidFontResourceLoader
import androidx.ui.text.font.Font
import kotlinx.coroutines.Dispatchers
import kotlin.coroutines.CoroutineContext
@@ -198,7 +196,7 @@
},
{ children ->
FontLoaderAmbient.Provider(
- value = AndroidFontResourceLoader(context),
+ value = composeView.fontLoader,
children = children
)
},
@@ -242,12 +240,8 @@
val FocusManagerAmbient = Ambient.of<FocusManager>()
-internal val TextInputServiceAmbient = Ambient.of<TextInputService?>()
+val TextInputServiceAmbient = Ambient.of<TextInputService?>()
-/**
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
val FontLoaderAmbient = Ambient.of<Font.ResourceLoader>()
/**
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt
index f3676fb..44e8da0 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt
@@ -16,6 +16,7 @@
package androidx.ui.core.selection
+import androidx.compose.Immutable
import androidx.ui.core.LayoutCoordinates
import androidx.ui.core.PxPosition
import androidx.ui.text.TextRange
@@ -24,6 +25,7 @@
/**
* Information about the current Selection.
*/
+@Immutable
data class Selection(
/**
* Information about the start of the selection.
@@ -48,6 +50,7 @@
/**
* Contains information about an anchor (start/end) of selection.
*/
+ @Immutable
data class AnchorInfo(
/**
* The coordinates of the graphical position for selection character offset.
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt
index 3891e24..ca3c9c1 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt
@@ -164,7 +164,7 @@
isStart = false,
areHandlesCrossed = handlesCrossed
),
- direction = textDelegate.getBidiRunDirection(Math.max(endOffset - 1, 0)),
+ direction = textDelegate.getBidiRunDirection(max(endOffset - 1, 0)),
offset = endOffset,
layoutCoordinates = if (containsWholeSelectionEnd) layoutCoordinates else null
),
@@ -293,7 +293,7 @@
val line = textDelegate.getLineForOffset(offset)
val offsetToCheck =
if (isStart && !areHandlesCrossed || !isStart && areHandlesCrossed) offset
- else Math.max(offset - 1, 0)
+ else max(offset - 1, 0)
val bidiRunDirection = textDelegate.getBidiRunDirection(offsetToCheck)
val paragraphDirection = textDelegate.getParagraphDirection(offset)
diff --git a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
index 9fad49a..3ce6d70 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
@@ -17,10 +17,12 @@
package androidx.ui.graphics.vector
import androidx.compose.Composable
+import androidx.ui.core.Alignment
import androidx.ui.core.Px
import androidx.ui.graphics.BlendMode
import androidx.ui.graphics.Brush
import androidx.ui.graphics.Color
+import androidx.ui.graphics.ScaleFit
import androidx.ui.graphics.StrokeCap
import androidx.ui.graphics.StrokeJoin
import java.util.Stack
@@ -377,7 +379,9 @@
fun DrawVector(
vectorImage: VectorAsset,
tintColor: Color = Color.Transparent,
- tintBlendMode: BlendMode = DefaultTintBlendMode
+ tintBlendMode: BlendMode = DefaultTintBlendMode,
+ alignment: Alignment = Alignment.Center,
+ fit: ScaleFit = ScaleFit.Fit
) {
DrawVector(
name = vectorImage.name,
@@ -386,7 +390,9 @@
defaultWidth = vectorImage.defaultWidth,
defaultHeight = vectorImage.defaultHeight,
tintColor = tintColor,
- tintBlendMode = tintBlendMode
+ tintBlendMode = tintBlendMode,
+ alignment = alignment,
+ scaleFit = fit
) { _, _ ->
RenderVectorGroup(group = vectorImage.root)
}
diff --git a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt
index 088fdc5..111a717 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt
@@ -27,13 +27,16 @@
import androidx.ui.core.IntPx
import androidx.ui.core.IntPxSize
import androidx.ui.core.Px
+import androidx.ui.core.PxSize
import androidx.ui.core.ambientDensity
import androidx.ui.core.withDensity
import androidx.ui.graphics.BlendMode
import androidx.ui.graphics.Brush
import androidx.ui.graphics.Color
+import androidx.ui.graphics.ScaleFit
import androidx.ui.graphics.StrokeCap
import androidx.ui.graphics.StrokeJoin
+import androidx.ui.graphics.withSave
import kotlin.math.ceil
/**
@@ -56,6 +59,7 @@
* @param[tintColor] Optional color used to tint this vector graphic
* @param[tintBlendMode] Optional blend mode used with [tintColor], default is [BlendMode.srcIn]
* @param[alignment] Specifies the placement of the vector within the drawing bounds
+ * @param[scaleFit] Specifies how the vector is to be scaled within the parent bounds
*/
@Composable
fun DrawVector(
@@ -66,6 +70,7 @@
tintColor: Color = DefaultTintColor,
tintBlendMode: BlendMode = DefaultTintBlendMode,
alignment: Alignment = DefaultAlignment,
+ scaleFit: ScaleFit = ScaleFit.Fit,
name: String = "",
children: @Composable() VectorScope.(viewportWidth: Float, viewportHeight: Float) -> Unit
) {
@@ -75,15 +80,16 @@
val vpWidth = if (viewportWidth == unset) widthPx.value else viewportWidth
val vpHeight = if (viewportHeight == unset) heightPx.value else viewportHeight
DrawVector(
- widthPx,
- heightPx,
- vpWidth,
- vpHeight,
- tintColor,
- tintBlendMode,
- alignment,
- name,
- children
+ defaultWidth = widthPx,
+ defaultHeight = heightPx,
+ viewportWidth = vpWidth,
+ viewportHeight = vpHeight,
+ tintColor = tintColor,
+ tintBlendMode = tintBlendMode,
+ alignment = alignment,
+ scaleFit = scaleFit,
+ name = name,
+ children = children
)
}
@@ -100,6 +106,7 @@
* @param[tintColor] Optional color used to tint this vector graphic
* @param[tintBlendMode] Optional blend mode used with [tintColor], default is [BlendMode.srcIn]
* @param[alignment] Specifies the placement of the vector within the drawing bounds
+ * @param[scaleFit] Specifies how the vector is to be scaled within the parent bounds
*/
@Composable
fun DrawVector(
@@ -110,6 +117,7 @@
tintColor: Color = DefaultTintColor,
tintBlendMode: BlendMode = DefaultTintBlendMode,
alignment: Alignment = DefaultAlignment,
+ scaleFit: ScaleFit = ScaleFit.Fit,
name: String = "",
children: @Composable() VectorScope.(viewportWidth: Float, viewportHeight: Float) -> Unit
) {
@@ -132,19 +140,33 @@
}
}
+ val vectorWidth = defaultWidth.value
+ val vectorHeight = defaultHeight.value
+ val vectorPxSize = PxSize(Px(vectorWidth), Px(vectorHeight))
+
Draw { canvas, parentSize ->
+ val parentWidth = parentSize.width.value
+ val parentHeight = parentSize.height.value
+ val scale = scaleFit.scale(vectorPxSize, parentSize)
+
val alignedPosition = alignment.align(
IntPxSize(
- IntPx(ceil(parentSize.width.value - defaultWidth.value).toInt()),
- IntPx(ceil(parentSize.height.value - defaultHeight.value).toInt())
+ IntPx(ceil(parentWidth - (vectorWidth * scale)).toInt()),
+ IntPx(ceil(parentHeight - (vectorHeight * scale)).toInt())
)
)
- val dx = alignedPosition.x.value.toFloat()
- val dy = alignedPosition.y.value.toFloat()
- canvas.translate(dx, dy)
- vector.draw(canvas, tintColor, tintBlendMode)
- canvas.translate(-dx, -dy)
+ val translateX = alignedPosition.x.value.toFloat()
+ val translateY = alignedPosition.y.value.toFloat()
+
+ // apply the scale to the root of the vector
+ vector.root.scaleX = (vectorWidth / viewportWidth) * scale
+ vector.root.scaleY = (vectorHeight / viewportHeight) * scale
+
+ canvas.withSave {
+ canvas.translate(translateX, translateY)
+ vector.draw(canvas, tintColor, tintBlendMode)
+ }
}
}
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt
index b39758d..6c4c2c8 100644
--- a/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt
@@ -64,11 +64,6 @@
private lateinit var layoutCoordinates: LayoutCoordinates
private lateinit var multiParagraphIntrinsics: MultiParagraphIntrinsics
- private val identityOffsetMap = object : OffsetMap {
- override fun originalToTransformed(offset: Int): Int = offset
- override fun transformedToOriginal(offset: Int): Int = offset
- }
-
/**
* Test implementation of offset map which doubles the offset in transformed text.
*/
@@ -100,7 +95,7 @@
value = InputState(text = "Hello, World", selection = selection),
selectionColor = selectionColor,
hasFocus = true,
- offsetMap = identityOffsetMap
+ offsetMap = OffsetMap.identityOffsetMap
)
verify(mDelegate, times(1)).paintBackground(
@@ -119,7 +114,7 @@
textDelegate = mDelegate,
value = InputState(text = "Hello, World", selection = cursor),
hasFocus = true,
- offsetMap = identityOffsetMap,
+ offsetMap = OffsetMap.identityOffsetMap,
selectionColor = Color.Blue
)
@@ -137,7 +132,7 @@
textDelegate = mDelegate,
value = InputState(text = "Hello, World", selection = cursor),
hasFocus = false,
- offsetMap = identityOffsetMap,
+ offsetMap = OffsetMap.identityOffsetMap,
selectionColor = Color.Blue
)
@@ -180,7 +175,7 @@
position,
mDelegate,
processor,
- identityOffsetMap,
+ OffsetMap.identityOffsetMap,
onValueChange,
textInputService,
dummyInputSessionToken,
@@ -209,7 +204,7 @@
position,
mDelegate,
processor,
- identityOffsetMap,
+ OffsetMap.identityOffsetMap,
onValueChange,
textInputService,
dummyInputSessionToken,
@@ -268,7 +263,7 @@
textInputService,
dummyInputSessionToken,
true /* hasFocus */,
- identityOffsetMap
+ OffsetMap.identityOffsetMap
)
verify(textInputService).notifyFocusedRect(eq(dummyInputSessionToken), any())
}
@@ -284,7 +279,7 @@
textInputService,
dummyInputSessionToken,
false /* hasFocus */,
- identityOffsetMap
+ OffsetMap.identityOffsetMap
)
verify(textInputService, never()).notifyFocusedRect(any(), any())
}
@@ -304,7 +299,7 @@
textInputService,
dummyInputSessionToken,
true /* hasFocus */,
- identityOffsetMap
+ OffsetMap.identityOffsetMap
)
verify(textInputService).notifyFocusedRect(eq(dummyInputSessionToken), any())
}
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt
index 47bcddc..e881c32 100644
--- a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt
@@ -33,8 +33,6 @@
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.never
import com.nhaarman.mockitokotlin2.verify
-import kotlinx.coroutines.ObsoleteCoroutinesApi
-import kotlinx.coroutines.test.TestCoroutineContext
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -45,12 +43,13 @@
// 1. More complex multi-pointer scenarios testing how consumption affects firing events
// 2. More complex multi-pointer scenarios testing how pointers effect consumption
-@ObsoleteCoroutinesApi
+@kotlinx.coroutines.ObsoleteCoroutinesApi
@RunWith(JUnit4::class)
class DoubleTapGestureDetectorTest {
private val DoubleTapTimeoutMillis = 100.milliseconds
- private val testContext = TestCoroutineContext()
+ @Suppress("DEPRECATION")
+ private val testContext = kotlinx.coroutines.test.TestCoroutineContext()
private val onDoubleTap: (PxPosition) -> Unit = mock()
private lateinit var mRecognizer: DoubleTapGestureRecognizer
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt
index 3b11a33..01bb32c 100644
--- a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt
@@ -35,20 +35,19 @@
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.never
import com.nhaarman.mockitokotlin2.verify
-import kotlinx.coroutines.ObsoleteCoroutinesApi
-import kotlinx.coroutines.test.TestCoroutineContext
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.util.concurrent.TimeUnit
-@ObsoleteCoroutinesApi
+@kotlinx.coroutines.ObsoleteCoroutinesApi
@RunWith(JUnit4::class)
class LongPressGestureDetectorTest {
private val LongPressTimeoutMillis = 100.milliseconds
- private val testContext = TestCoroutineContext()
+ @Suppress("DEPRECATION")
+ private val testContext = kotlinx.coroutines.test.TestCoroutineContext()
private val onLongPress: (PxPosition) -> Unit = mock()
private lateinit var mRecognizer: LongPressGestureRecognizer
diff --git a/ui/ui-layout/api/0.1.0-dev03.txt b/ui/ui-layout/api/0.1.0-dev03.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/0.1.0-dev03.txt
+++ b/ui/ui-layout/api/0.1.0-dev03.txt
@@ -126,10 +126,10 @@
public final class FlexKt {
ctor public FlexKt();
- method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+ method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
- method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+ method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
}
@androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/current.txt b/ui/ui-layout/api/current.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/current.txt
+++ b/ui/ui-layout/api/current.txt
@@ -126,10 +126,10 @@
public final class FlexKt {
ctor public FlexKt();
- method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+ method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
- method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+ method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
}
@androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt
@@ -126,10 +126,10 @@
public final class FlexKt {
ctor public FlexKt();
- method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+ method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
- method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+ method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
}
@androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/public_plus_experimental_current.txt b/ui/ui-layout/api/public_plus_experimental_current.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/public_plus_experimental_current.txt
+++ b/ui/ui-layout/api/public_plus_experimental_current.txt
@@ -126,10 +126,10 @@
public final class FlexKt {
ctor public FlexKt();
- method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+ method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
- method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+ method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
}
@androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/restricted_0.1.0-dev03.txt b/ui/ui-layout/api/restricted_0.1.0-dev03.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-layout/api/restricted_0.1.0-dev03.txt
@@ -126,10 +126,10 @@
public final class FlexKt {
ctor public FlexKt();
- method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+ method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
- method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+ method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
}
@androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/restricted_current.txt b/ui/ui-layout/api/restricted_current.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/restricted_current.txt
+++ b/ui/ui-layout/api/restricted_current.txt
@@ -126,10 +126,10 @@
public final class FlexKt {
ctor public FlexKt();
- method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+ method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
- method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+ method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
}
@androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt
index 62861c1..c989ad36 100644
--- a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt
+++ b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt
@@ -52,7 +52,7 @@
import androidx.ui.core.VerticalAlignmentLine
import androidx.ui.core.sp
import androidx.ui.layout.AlignmentLineOffset
-import androidx.ui.layout.CrossAxisAlignment
+import androidx.ui.layout.Gravity
import androidx.ui.layout.Wrap
import androidx.ui.layout.samples.DrawRectangle
import androidx.ui.layout.samples.SizedRectangle
@@ -387,9 +387,9 @@
@Composable
fun RowBaselineAlignment() {
- Row(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(FirstBaseline)) {
- Text("First text")
- Column {
+ Row {
+ Text("First text", modifier = Gravity.RelativeToSiblings(FirstBaseline))
+ Column(modifier = Gravity.RelativeToSiblings(FirstBaseline)) {
SizedRectangle(color = Color.Blue, width = 10.dp, height = 50.dp)
Padding(30.dp) {
Text("Second text", style = TextStyle(fontSize = 45.sp))
diff --git a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt
index c46cab9..198ed8c 100644
--- a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt
+++ b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt
@@ -23,7 +23,6 @@
import androidx.ui.core.dp
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.HeightSpacer
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.layout.Row
@@ -32,10 +31,12 @@
import androidx.ui.graphics.Color
import androidx.ui.text.TextStyle
import androidx.compose.Composable
+import androidx.ui.core.Modifier
import androidx.ui.core.setContent
import androidx.ui.core.sp
import androidx.ui.layout.ExpandedHeight
import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
import androidx.ui.layout.samples.DrawRectangle
class LayoutActivity : Activity() {
@@ -64,10 +65,7 @@
@Composable
fun LayoutDemo() {
val lightGrey = Color(0xFFCFD8DC)
- Column(
- mainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(mainAxisAlignment = MainAxisAlignment.Start) {
Text(text = "Row", style = TextStyle(fontSize = 48.sp))
ContainerWithBackground(width = ExampleSize, color = lightGrey) {
Row(ExpandedWidth) {
@@ -97,22 +95,16 @@
}
HeightSpacer(height = 24.dp)
ContainerWithBackground(width = ExampleSize, color = lightGrey) {
- Row(
- ExpandedWidth,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Row(ExpandedWidth) {
PurpleSquare()
CyanSquare()
}
}
HeightSpacer(height = 24.dp)
ContainerWithBackground(width = ExampleSize, color = lightGrey) {
- Row(
- ExpandedWidth,
- crossAxisAlignment = CrossAxisAlignment.End
- ) {
- PurpleSquare()
- CyanSquare()
+ Row(ExpandedWidth) {
+ PurpleSquare(Gravity.Bottom)
+ CyanSquare(Gravity.Bottom)
}
}
HeightSpacer(height = 24.dp)
@@ -146,22 +138,16 @@
}
WidthSpacer(width = 24.dp)
ContainerWithBackground(height = ExampleSize, color = lightGrey) {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(ExpandedHeight) {
PurpleSquare()
CyanSquare()
}
}
WidthSpacer(width = 24.dp)
ContainerWithBackground(height = ExampleSize, color = lightGrey) {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.End
- ) {
- PurpleSquare()
- CyanSquare()
+ Column(ExpandedHeight) {
+ PurpleSquare(Gravity.End)
+ CyanSquare(Gravity.End)
}
}
}
@@ -169,15 +155,15 @@
}
@Composable
-fun PurpleSquare() {
- Container(width = BigSize, height = BigSize) {
+fun PurpleSquare(modifier: Modifier = Modifier.None) {
+ Container(width = BigSize, height = BigSize, modifier = modifier) {
DrawRectangle(color = Color(0xFF6200EE))
}
}
@Composable
-fun CyanSquare() {
- Container(width = SmallSize, height = SmallSize) {
+fun CyanSquare(modifier: Modifier = Modifier.None) {
+ Container(width = SmallSize, height = SmallSize, modifier = modifier) {
DrawRectangle(color = Color(0xFF03DAC6))
}
}
diff --git a/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt b/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt
index 1063a67..14f1f30 100644
--- a/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt
+++ b/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt
@@ -30,6 +30,7 @@
import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.DpConstraints
import androidx.ui.layout.ExpandedHeight
+import androidx.ui.layout.ExpandedWidth
import androidx.ui.layout.FlexRow
import androidx.ui.layout.MaxIntrinsicHeight
import androidx.ui.layout.MaxIntrinsicWidth
@@ -43,7 +44,7 @@
* Here [MinIntrinsicWidth] is adding a speculative width measurement pass for the [Column],
* whose minimum intrinsic width will correspond to the preferred width of the largest
* [ConstrainedBox]. Then [MinIntrinsicWidth] will measure the [Column] with tight width, the same
- * as the premeasured minimum intrinsic width, which due to [CrossAxisAlignment.Stretch] will force
+ * as the premeasured minimum intrinsic width, which due to [ExpandedWidth] will force
* the [ConstrainedBox]s to use the same width.
*/
@Sampled
@@ -51,17 +52,23 @@
fun SameWidthBoxes() {
Wrap {
MinIntrinsicWidth {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Stretch
- ) {
- ConstrainedBox(DpConstraints.tightConstraints(width = 20.dp, height = 10.dp)) {
+ Column(ExpandedHeight) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(width = 20.dp, height = 10.dp),
+ modifier = ExpandedWidth
+ ) {
DrawShape(RectangleShape, Color.Gray)
}
- ConstrainedBox(DpConstraints.tightConstraints(width = 30.dp, height = 10.dp)) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(width = 30.dp, height = 10.dp),
+ modifier = ExpandedWidth
+ ) {
DrawShape(RectangleShape, Color.Blue)
}
- ConstrainedBox(DpConstraints.tightConstraints(width = 10.dp, height = 10.dp)) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(width = 10.dp, height = 10.dp),
+ modifier = ExpandedWidth
+ ) {
DrawShape(RectangleShape, Color.Magenta)
}
}
@@ -106,7 +113,7 @@
* Here [MaxIntrinsicWidth] is adding a speculative width measurement pass for the [Column],
* whose maximum intrinsic width will correspond to the preferred width of the largest
* [ConstrainedBox]. Then [MaxIntrinsicWidth] will measure the [Column] with tight width, the same
- * as the premeasured maximum intrinsic width, which due to [CrossAxisAlignment.Stretch] will force
+ * as the premeasured maximum intrinsic width, which due to [ExpandedWidth] modifiers will force
* the [ConstrainedBox]s to use the same width.
*/
@Sampled
@@ -114,19 +121,16 @@
fun SameWidthTextBoxes() {
Wrap {
MaxIntrinsicWidth {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Stretch
- ) {
- Wrap {
+ Column(ExpandedHeight) {
+ Container(ExpandedWidth) {
DrawShape(RectangleShape, Color.Gray)
Text("Short text")
}
- Wrap {
+ Container(ExpandedWidth) {
DrawShape(RectangleShape, Color.Blue)
Text("Extremely long text giving the width of its siblings")
}
- Wrap {
+ Container(ExpandedWidth) {
DrawShape(RectangleShape, Color.Magenta)
Text("Medium length text")
}
diff --git a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt
index e20dd16..81a145d 100644
--- a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt
+++ b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt
@@ -553,107 +553,6 @@
// region Cross axis alignment tests in Row
@Test
- fun testRow_withStartCrossAxisAlignment() = withDensity(density) {
- val sizeDp = 50.dp
- val size = sizeDp.toIntPx()
-
- val drawLatch = CountDownLatch(2)
- val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
- val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
- show {
- Align(Alignment.CenterLeft) {
- Row(crossAxisAlignment = CrossAxisAlignment.Start) {
- Container(width = sizeDp, height = sizeDp) {
- OnPositioned( coordinates ->
- childSize[0] = coordinates.size
- childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
-
- Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
- OnPositioned( coordinates ->
- childSize[1] = coordinates.size
- childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
- }
- }
- }
- drawLatch.await(1, TimeUnit.SECONDS)
-
- val root = findAndroidComposeView()
- waitForDraw(root)
-
- assertEquals(PxSize(size, size), childSize[0])
- assertEquals(
- PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
- childSize[1]
- )
- assertEquals(
- PxPosition(0.px, (root.height.px / 2 - size.toPx()).round().toPx()),
- childPosition[0]
- )
- assertEquals(
- PxPosition(size.toPx(), (root.height.px / 2 - size.toPx()).round().toPx()),
- childPosition[1]
- )
- }
-
- @Test
- fun testRow_withEndCrossAxisAlignment() = withDensity(density) {
- val sizeDp = 50.dp
- val size = sizeDp.toIntPx()
-
- val drawLatch = CountDownLatch(2)
- val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
- val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
- show {
- Align(Alignment.CenterLeft) {
- Row(crossAxisAlignment = CrossAxisAlignment.End) {
- Container(width = sizeDp, height = sizeDp) {
- OnPositioned( coordinates ->
- childSize[0] = coordinates.size
- childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
-
- Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
- OnPositioned( coordinates ->
- childSize[1] = coordinates.size
- childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
- }
- }
- }
- drawLatch.await(1, TimeUnit.SECONDS)
-
- val root = findAndroidComposeView()
- waitForDraw(root)
-
- assertEquals(PxSize(size, size), childSize[0])
- assertEquals(
- PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
- childSize[1]
- )
- assertEquals(
- PxPosition(
- 0.px, ((root.height.px + (sizeDp.toPx() * 2)
- .round().toPx()) / 2 - size.toPx()).round().toPx()
- ),
- childPosition[0]
- )
- assertEquals(
- PxPosition(size.toPx(), (root.height.px / 2 - size.toPx()).round().toPx()),
- childPosition[1]
- )
- }
-
- @Test
fun testRow_withStretchCrossAxisAlignment() = withDensity(density) {
val sizeDp = 50.dp
val size = sizeDp.toIntPx()
@@ -663,8 +562,8 @@
val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
show {
Align(Alignment.CenterLeft) {
- Row(crossAxisAlignment = CrossAxisAlignment.Stretch) {
- Container(width = sizeDp, height = sizeDp) {
+ Row {
+ Container(width = sizeDp, height = sizeDp, modifier = ExpandedHeight) {
OnPositioned( coordinates ->
childSize[0] = coordinates.size
childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -672,7 +571,11 @@
})
}
- Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
+ Container(
+ width = (sizeDp * 2),
+ height = (sizeDp * 2),
+ modifier = ExpandedHeight
+ ) {
OnPositioned( coordinates ->
childSize[1] = coordinates.size
childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -841,108 +744,6 @@
// region Cross axis alignment tests in Column
@Test
- fun testColumn_withStartCrossAxisAlignment() = withDensity(density) {
- val sizeDp = 50.dp
- val size = sizeDp.toIntPx()
-
- val drawLatch = CountDownLatch(2)
- val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
- val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
- show {
- Align(Alignment.TopCenter) {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
- Container(width = sizeDp, height = sizeDp) {
- OnPositioned( coordinates ->
- childSize[0] = coordinates.size
- childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
-
- Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
- OnPositioned( coordinates ->
- childSize[1] = coordinates.size
- childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
- }
- }
- }
- drawLatch.await(1, TimeUnit.SECONDS)
-
- val root = findAndroidComposeView()
- waitForDraw(root)
-
- assertEquals(PxSize(size, size), childSize[0])
- assertEquals(
- PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
- childSize[1]
- )
- assertEquals(
- PxPosition((root.width.px / 2 - size.toPx()).round().toPx(), 0.px),
- childPosition[0]
- )
- assertEquals(
- PxPosition((root.width.px / 2 - size.toPx()).round().toPx(), size.toPx()),
- childPosition[1]
- )
- }
-
- @Test
- fun testColumn_withEndCrossAxisAlignment() = withDensity(density) {
- val sizeDp = 50.dp
- val size = sizeDp.toIntPx()
-
- val drawLatch = CountDownLatch(2)
- val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
- val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
- show {
- Align(Alignment.TopCenter) {
- Column(crossAxisAlignment = CrossAxisAlignment.End) {
- Container(width = sizeDp, height = sizeDp) {
- OnPositioned( coordinates ->
- childSize[0] = coordinates.size
- childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
-
- Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
- OnPositioned( coordinates ->
- childSize[1] = coordinates.size
- childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- drawLatch.countDown()
- })
- }
- }
- }
- }
- drawLatch.await(1, TimeUnit.SECONDS)
-
- val root = findAndroidComposeView()
- waitForDraw(root)
-
- assertEquals(PxSize(size, size), childSize[0])
- assertEquals(
- PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
- childSize[1]
- )
- assertEquals(
- PxPosition(
- (((root.width.px + (sizeDp.toPx() * 2)
- .round().toPx()) / 2).round() - size).toPx(),
- 0.px
- ),
- childPosition[0]
- )
- assertEquals(
- PxPosition((root.width.px / 2 - size.toPx()).round().toPx(), size.toPx()),
- childPosition[1]
- )
- }
-
- @Test
fun testColumn_withStretchCrossAxisAlignment() = withDensity(density) {
val sizeDp = 50.dp
val size = sizeDp.toIntPx()
@@ -952,8 +753,8 @@
val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
show {
Align(Alignment.TopCenter) {
- Column(crossAxisAlignment = CrossAxisAlignment.Stretch) {
- Container(width = sizeDp, height = sizeDp) {
+ Column {
+ Container(width = sizeDp, height = sizeDp, modifier = ExpandedWidth) {
OnPositioned( coordinates ->
childSize[0] = coordinates.size
childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -961,7 +762,9 @@
})
}
- Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
+ Container(
+ width = (sizeDp * 2), height = (sizeDp * 2), modifier = ExpandedWidth
+ ) {
OnPositioned( coordinates ->
childSize[1] = coordinates.size
childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -2652,40 +2455,24 @@
) { }
}
}, @Composable {
- Row(
- ExpandedWidth,
- mainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.Start) {
Container(AspectRatio(2f)) { }
ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
}
}, @Composable {
- Row(
- ExpandedWidth,
- mainAxisAlignment = MainAxisAlignment.Center,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- Container(AspectRatio(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+ Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.Center) {
+ Container(Gravity.Center wraps AspectRatio(2f)) { }
+ ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), Gravity.Center) { }
}
}, @Composable {
- Row(
- ExpandedWidth,
- mainAxisAlignment = MainAxisAlignment.End,
- crossAxisAlignment = CrossAxisAlignment.End
- ) {
- Container(AspectRatio(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+ Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.End) {
+ Container(Gravity.Bottom wraps AspectRatio(2f)) { }
+ ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), Gravity.Bottom) { }
}
}, @Composable {
- Row(
- ExpandedWidth,
- mainAxisAlignment = MainAxisAlignment.SpaceAround,
- crossAxisAlignment = CrossAxisAlignment.Stretch
- ) {
- Container(AspectRatio(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+ Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+ Container(ExpandedHeight wraps AspectRatio(2f)) { }
+ ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), ExpandedHeight) { }
}
}, @Composable {
Row(
@@ -2746,44 +2533,65 @@
ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Gravity.Bottom) { }
}
}, @Composable {
- Row(
- mainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Row(mainAxisAlignment = MainAxisAlignment.Start) {
ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
Container(AspectRatio(2f) wraps Flexible(2f)) { }
ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
}
}, @Composable {
- Row(
- mainAxisAlignment = MainAxisAlignment.Center,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
- Container(AspectRatio(2f) wraps Flexible(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
+ Row(mainAxisAlignment = MainAxisAlignment.Center) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+ modifier = Flexible(3f) wraps Gravity.Center
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 40.dp),
+ modifier = Flexible(2f) wraps Gravity.Center
+ ) { }
+ Container(
+ AspectRatio(2f) wraps Flexible(2f) wraps Gravity.Center
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+ modifier = Gravity.Center
+ ) { }
}
}, @Composable {
- Row(
- mainAxisAlignment = MainAxisAlignment.End,
- crossAxisAlignment = CrossAxisAlignment.End
- ) {
- ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
- Container(AspectRatio(2f) wraps Flexible(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
+ Row(mainAxisAlignment = MainAxisAlignment.End) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+ modifier = Flexible(3f) wraps Gravity.Bottom
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 40.dp),
+ modifier = Flexible(2f) wraps Gravity.Bottom
+ ) { }
+ Container(
+ AspectRatio(2f) wraps Flexible(2f) wraps Gravity.Bottom
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+ modifier = Gravity.Bottom
+ ) { }
}
}, @Composable {
- Row(
- mainAxisAlignment = MainAxisAlignment.SpaceAround,
- crossAxisAlignment = CrossAxisAlignment.Stretch
- ) {
- ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
- Container(AspectRatio(2f) wraps Flexible(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
+ Row(mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+ modifier = Flexible(3f) wraps ExpandedHeight
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 40.dp),
+ modifier = Flexible(2f) wraps ExpandedHeight
+ ) { }
+ Container(
+ AspectRatio(2f) wraps Flexible(2f) wraps ExpandedHeight
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+ modifier = ExpandedHeight
+ ) { }
}
}, @Composable {
Row(mainAxisAlignment = MainAxisAlignment.SpaceBetween) {
@@ -2873,40 +2681,24 @@
ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
}
}, @Composable {
- Column(
- ExpandedHeight,
- mainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.Start) {
Container(AspectRatio(2f)) { }
ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
}
}, @Composable {
- Column(
- ExpandedHeight,
- mainAxisAlignment = MainAxisAlignment.Center,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- Container(AspectRatio(2f)) { }
+ Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.Center) {
+ Container(Gravity.Center wraps AspectRatio(2f)) { }
ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
}
}, @Composable {
- Column(
- ExpandedHeight,
- mainAxisAlignment = MainAxisAlignment.End,
- crossAxisAlignment = CrossAxisAlignment.End
- ) {
- Container(AspectRatio(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+ Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.End) {
+ Container(Gravity.End wraps AspectRatio(2f)) { }
+ ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), Gravity.End) { }
}
}, @Composable {
- Column(
- ExpandedHeight,
- mainAxisAlignment = MainAxisAlignment.SpaceAround,
- crossAxisAlignment = CrossAxisAlignment.Stretch
- ) {
- Container(AspectRatio(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+ Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+ Container(ExpandedWidth wraps AspectRatio(2f)) { }
+ ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), ExpandedWidth) { }
}
}, @Composable {
Column(
@@ -2967,44 +2759,65 @@
ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Gravity.End) { }
}
}, @Composable {
- Column(
- mainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(mainAxisAlignment = MainAxisAlignment.Start) {
ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
}
}, @Composable {
- Column(
- mainAxisAlignment = MainAxisAlignment.Center,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
- Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
+ Column(mainAxisAlignment = MainAxisAlignment.Center) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+ modifier = Flexible(3f) wraps Gravity.Center
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(40.dp, 30.dp),
+ modifier = Flexible(2f) wraps Gravity.Center
+ ) { }
+ Container(
+ AspectRatio(0.5f) wraps Flexible(2f) wraps Gravity.Center
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+ modifier = Gravity.Center
+ ) { }
}
}, @Composable {
- Column(
- mainAxisAlignment = MainAxisAlignment.End,
- crossAxisAlignment = CrossAxisAlignment.End
- ) {
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
- Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
+ Column(mainAxisAlignment = MainAxisAlignment.End) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+ modifier = Flexible(3f) wraps Gravity.End
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(40.dp, 30.dp),
+ modifier = Flexible(2f) wraps Gravity.End
+ ) { }
+ Container(
+ AspectRatio(0.5f) wraps Flexible(2f) wraps Gravity.End
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+ modifier = Gravity.End
+ ) { }
}
}, @Composable {
- Column(
- mainAxisAlignment = MainAxisAlignment.SpaceAround,
- crossAxisAlignment = CrossAxisAlignment.Stretch
- ) {
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
- Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
- ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
+ Column(mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+ modifier = Flexible(3f) wraps ExpandedWidth
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(40.dp, 30.dp),
+ modifier = Flexible(2f) wraps ExpandedWidth
+ ) { }
+ Container(
+ AspectRatio(0.5f) wraps Flexible(2f) wraps ExpandedWidth
+ ) { }
+ ConstrainedBox(
+ constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+ modifier = ExpandedWidth
+ ) { }
}
}, @Composable {
Column(mainAxisAlignment = MainAxisAlignment.SpaceBetween) {
@@ -3086,10 +2899,7 @@
}
}
}, @Composable {
- FlexRow(
- mainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ FlexRow(mainAxisAlignment = MainAxisAlignment.Start) {
expanded(flex = 3f) {
ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
}
@@ -3253,10 +3063,7 @@
}
}
}, @Composable {
- FlexColumn(
- mainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ FlexColumn(mainAxisAlignment = MainAxisAlignment.Start) {
expanded(flex = 3f) {
ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
}
@@ -3403,32 +3210,34 @@
}
@Test
- fun testRow_alignmentUsingAlignmentKey() = withDensity(density) {
+ fun testFlexRow_alignmentUsingAlignmentKey() = withDensity(density) {
val TestAlignmentLine = HorizontalAlignmentLine(::min)
val rowSize = Ref<PxSize>()
val childPosition = arrayOf<Ref<PxPosition>>(Ref(), Ref(), Ref())
val layoutLatch = CountDownLatch(4)
show {
Wrap {
- Row(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)) {
- SaveLayoutInfo(rowSize, Ref(), layoutLatch)
- OnChildPositioned({ coordinates ->
- childPosition[0].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- layoutLatch.countDown()
- }) {
- FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 10.ipx))
- }
- OnChildPositioned({ coordinates ->
- childPosition[1].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- layoutLatch.countDown()
- }) {
- FixedSizeLayout(10.ipx, 10.ipx, mapOf())
- }
- OnChildPositioned({ coordinates ->
- childPosition[2].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- layoutLatch.countDown()
- }) {
- FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 20.ipx))
+ FlexRow(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)) {
+ inflexible {
+ SaveLayoutInfo(rowSize, Ref(), layoutLatch)
+ OnChildPositioned({ coordinates ->
+ childPosition[0].value = coordinates.localToGlobal(PxPosition.Origin)
+ layoutLatch.countDown()
+ }) {
+ FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 10.ipx))
+ }
+ OnChildPositioned({ coordinates ->
+ childPosition[1].value = coordinates.localToGlobal(PxPosition.Origin)
+ layoutLatch.countDown()
+ }) {
+ FixedSizeLayout(10.ipx, 10.ipx, mapOf())
+ }
+ OnChildPositioned({ coordinates ->
+ childPosition[2].value = coordinates.localToGlobal(PxPosition.Origin)
+ layoutLatch.countDown()
+ }) {
+ FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 20.ipx))
+ }
}
}
}
@@ -3442,32 +3251,36 @@
}
@Test
- fun testColumn_alignmentUsingAlignmentKey() = withDensity(density) {
+ fun testFlexColumn_alignmentUsingAlignmentKey() = withDensity(density) {
val TestAlignmentLine = VerticalAlignmentLine(::min)
val columnSize = Ref<PxSize>()
val childPosition = arrayOf<Ref<PxPosition>>(Ref(), Ref(), Ref())
val layoutLatch = CountDownLatch(4)
show {
Wrap {
- Column(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)) {
- SaveLayoutInfo(columnSize, Ref(), layoutLatch)
- OnChildPositioned({ coordinates ->
- childPosition[0].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- layoutLatch.countDown()
- }) {
- FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 10.ipx))
- }
- OnChildPositioned({ coordinates ->
- childPosition[1].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- layoutLatch.countDown()
- }) {
- FixedSizeLayout(10.ipx, 10.ipx, mapOf())
- }
- OnChildPositioned({ coordinates ->
- childPosition[2].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
- layoutLatch.countDown()
- }) {
- FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 20.ipx))
+ FlexColumn(
+ crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)
+ ) {
+ inflexible {
+ SaveLayoutInfo(columnSize, Ref(), layoutLatch)
+ OnChildPositioned({ coordinates ->
+ childPosition[0].value = coordinates.localToGlobal(PxPosition.Origin)
+ layoutLatch.countDown()
+ }) {
+ FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 10.ipx))
+ }
+ OnChildPositioned({ coordinates ->
+ childPosition[1].value = coordinates.localToGlobal(PxPosition.Origin)
+ layoutLatch.countDown()
+ }) {
+ FixedSizeLayout(10.ipx, 10.ipx, mapOf())
+ }
+ OnChildPositioned({ coordinates ->
+ childPosition[2].value = coordinates.localToGlobal(PxPosition.Origin)
+ layoutLatch.countDown()
+ }) {
+ FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 20.ipx))
+ }
}
}
}
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt
index 1deede0..a3d795e3 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt
@@ -311,21 +311,18 @@
*
* @param mainAxisAlignment The alignment of the layout's children in main axis direction.
* Default is [MainAxisAlignment.Start].
- * @param crossAxisAlignment The alignment of the layout's children in cross axis direction.
- * Default is [CrossAxisAlignment.Start].
*/
@Composable
fun Row(
modifier: Modifier = Modifier.None,
mainAxisAlignment: MainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.Start,
children: @Composable() RowScope.() -> Unit
) {
FlexLayout(
orientation = LayoutOrientation.Horizontal,
modifier = modifier,
mainAxisAlignment = mainAxisAlignment,
- crossAxisAlignment = crossAxisAlignment,
+ crossAxisAlignment = CrossAxisAlignment.Start,
crossAxisSize = LayoutSize.Wrap,
children = { RowScope().children() }
)
@@ -344,21 +341,18 @@
*
* @param mainAxisAlignment The alignment of the layout's children in main axis direction.
* Default is [MainAxisAlignment.Start].
- * @param crossAxisAlignment The alignment of the layout's children in cross axis direction.
- * Default is [CrossAxisAlignment.Start].
*/
@Composable
fun Column(
modifier: Modifier = Modifier.None,
mainAxisAlignment: MainAxisAlignment = MainAxisAlignment.Start,
- crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.Start,
children: @Composable() ColumnScope.() -> Unit
) {
FlexLayout(
orientation = LayoutOrientation.Vertical,
modifier = modifier,
mainAxisAlignment = mainAxisAlignment,
- crossAxisAlignment = crossAxisAlignment,
+ crossAxisAlignment = CrossAxisAlignment.Start,
crossAxisSize = LayoutSize.Wrap,
children = { ColumnScope().children() }
)
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt
index 414ba6f..672fc95 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt
@@ -24,7 +24,6 @@
import androidx.ui.core.dp
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.FlexColumn
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.material.RadioGroup
@@ -94,8 +93,7 @@
flexible(1f) {
Column(
ExpandedHeight,
- mainAxisAlignment = MainAxisAlignment.SpaceBetween,
- crossAxisAlignment = CrossAxisAlignment.Center
+ mainAxisAlignment = MainAxisAlignment.SpaceBetween
) {
DemoText("TopAppBar options")
RadioGroup {
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt
index 43e54c6..5af9694 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt
@@ -37,7 +37,6 @@
import androidx.compose.unaryPlus
import androidx.ui.layout.Center
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.ExpandedHeight
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.material.Button
@@ -54,11 +53,7 @@
override fun materialContent() {
val onClick: () -> Unit = { Log.e("ButtonDemo", "onClick") }
Center {
- Column(
- ExpandedHeight,
- mainAxisAlignment = MainAxisAlignment.SpaceEvenly,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
+ Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.SpaceEvenly) {
ContainedButtonSample(onClick)
OutlinedButtonSample(onClick)
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt
index 4ae3b55..37bc67d 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt
@@ -24,8 +24,8 @@
import androidx.ui.graphics.Color
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.EdgeInsets
+import androidx.ui.layout.Gravity
import androidx.ui.layout.HeightSpacer
import androidx.ui.layout.Row
import androidx.ui.layout.WidthSpacer
@@ -77,15 +77,17 @@
val avatarSize = ItemSize - ItemPadding * 2
val textStyle = (+MaterialTheme.typography()).body1
Container(height = ItemSize, padding = EdgeInsets(ItemPadding)) {
- Row(crossAxisAlignment = CrossAxisAlignment.Center) {
+ Row {
if (color != null) {
ColoredRect(
width = avatarSize,
height = avatarSize,
- color = color)
+ color = color,
+ modifier = Gravity.Center
+ )
WidthSpacer(width = ItemPadding)
}
- Text(text = text, style = textStyle)
+ Text(text = text, style = textStyle, modifier = Gravity.Center)
}
}
}
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt
index b294606..bb85e5b 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt
@@ -21,8 +21,8 @@
import androidx.ui.graphics.imageFromResource
import androidx.ui.layout.Center
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.ExpandedHeight
+import androidx.ui.layout.Gravity
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.material.FloatingActionButton
@@ -33,14 +33,18 @@
val icon = imageFromResource(resources, R.drawable.ic_favorite)
Center {
val onClick: () -> Unit = { Log.e("FABDemo", "onClick") }
- Column(
- ExpandedHeight,
- mainAxisAlignment = MainAxisAlignment.SpaceEvenly,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
- FloatingActionButton(icon = icon, >
- FloatingActionButton(text = "EXTENDED", >
- FloatingActionButton(icon = icon, text = "ADD TO FAVS", >
+ Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.SpaceEvenly) {
+ FloatingActionButton(icon = icon, modifier = Gravity.Center)
+ FloatingActionButton(
+ text = "EXTENDED",
+ >
+ modifier = Gravity.Center
+ )
+ FloatingActionButton(
+ icon = icon, text = "ADD TO FAVS",
+ >
+ modifier = Gravity.Center
+ )
}
}
}
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt
index d4d3b78..5fd2c06 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt
@@ -22,7 +22,6 @@
import androidx.ui.core.dp
import androidx.ui.graphics.Color
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.EdgeInsets
import androidx.ui.layout.Padding
import androidx.ui.material.MaterialTheme
@@ -42,7 +41,7 @@
Surface(color = Color.White) {
Padding(padding = padding) {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
Text(text = "Checkbox", style = headerStyle)
Padding(padding = padding) {
TriStateCheckboxSample()
diff --git a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt
index 3ee7de7..cb1c976 100644
--- a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt
+++ b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt
@@ -22,8 +22,8 @@
import androidx.ui.core.dp
import androidx.ui.foundation.shape.RectangleShape
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.EdgeInsets
+import androidx.ui.layout.ExpandedWidth
import androidx.ui.layout.Spacing
import androidx.ui.material.AlertDialog
import androidx.ui.material.Button
@@ -43,12 +43,17 @@
text = { Text(bodyText) },
buttons = {
val style = TextButtonStyle(RectangleShape).copy(paddings = EdgeInsets(16.dp))
- Column(crossAxisAlignment = CrossAxisAlignment.Stretch) {
+ Column {
Divider(
Spacing(left = 12.dp, right = 12.dp),
color = (+MaterialTheme.colors()).onSurface.copy(alpha = 0.2f)
)
- Button(text = buttonText, style = style)
+ Button(
+ text = buttonText,
+ >
+ style = style,
+ modifier = ExpandedWidth
+ )
}
}
)
diff --git a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt
index 163762b..93ecb03 100644
--- a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt
+++ b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt
@@ -28,10 +28,10 @@
import androidx.ui.graphics.Color
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.ExpandedWidth
import androidx.ui.layout.FixedSpacer
import androidx.ui.layout.FlexRow
+import androidx.ui.layout.Gravity
import androidx.ui.layout.HeightSpacer
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.layout.Row
@@ -159,9 +159,17 @@
Container(height = 300.dp, expanded = true) {
DrawAnimatedCircle(accountsProportion, colors)
}
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
- Text(text = "Total", style = (+MaterialTheme.typography()).body1)
- Text(text = "$12,132.49", style = (+MaterialTheme.typography()).h3)
+ Column {
+ Text(
+ text = "Total",
+ style = (+MaterialTheme.typography()).body1,
+ modifier = Gravity.Center
+ )
+ Text(
+ text = "$12,132.49",
+ style = (+MaterialTheme.typography()).h3,
+ modifier = Gravity.Center
+ )
}
}
}
@@ -210,7 +218,7 @@
inflexible {
AccountIndicator(color = color)
WidthSpacer(width = 8.dp)
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
Text(text = name, style = (+MaterialTheme.typography()).body1)
Text(text = "•••••$number", style = (+MaterialTheme.typography()).subtitle1)
}
@@ -289,9 +297,17 @@
Container(height = 300.dp, expanded = true) {
DrawAnimatedCircle(accountsProportion, colors)
}
- Column(crossAxisAlignment = CrossAxisAlignment.Center) {
- Text(text = "Due", style = (+MaterialTheme.typography()).body1)
- Text(text = "$1,810.00", style = (+MaterialTheme.typography()).h3)
+ Column {
+ Text(
+ text = "Due",
+ style = (+MaterialTheme.typography()).body1,
+ modifier = Gravity.Center
+ )
+ Text(
+ text = "$1,810.00",
+ style = (+MaterialTheme.typography()).h3,
+ modifier = Gravity.Center
+ )
}
}
}
diff --git a/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt b/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt
index 9fc9fc9..ef10226 100644
--- a/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt
+++ b/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt
@@ -40,7 +40,6 @@
import androidx.ui.layout.Center
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.EdgeInsets
import androidx.ui.layout.FlexColumn
import androidx.ui.layout.Padding
@@ -48,6 +47,7 @@
import androidx.ui.material.TabRow
import androidx.ui.graphics.Image
import androidx.ui.layout.ExpandedHeight
+import androidx.ui.layout.Gravity
import androidx.ui.material.MaterialTheme
@Sampled
@@ -289,14 +289,15 @@
fun FancyTab(title: String, onClick: () -> Unit, selected: Boolean) {
MutuallyExclusiveSetItem(selected = selected, {
Container(height = 50.dp, padding = EdgeInsets(10.dp)) {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
+ Column(ExpandedHeight) {
val color = if (selected) Color.Red else Color.Gray
- ColoredRect(height = 10.dp, width = 10.dp, color = color)
+ ColoredRect(height = 10.dp, width = 10.dp, color = color, modifier = Gravity.Center)
Padding(5.dp) {
- Text(text = title, style = (+MaterialTheme.typography()).body1)
+ Text(
+ text = title,
+ style = (+MaterialTheme.typography()).body1,
+ modifier = Gravity.Center
+ )
}
}
}
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt b/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt
index f84da65..4959f59 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt
@@ -25,7 +25,6 @@
import androidx.ui.foundation.shape.corner.RoundedCornerShape
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.EdgeInsets
import androidx.ui.layout.ExpandedWidth
import androidx.ui.layout.HeightSpacer
@@ -118,7 +117,7 @@
MaterialTheme(colors = currentColors, typography = currentTypography) {
Surface(shape = AlertDialogShape) {
Container(width = AlertDialogWidth) {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
if (title != null) {
Container(
alignment = Alignment.CenterLeft,
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt b/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt
index c1b33c1..76f5268 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt
@@ -38,9 +38,9 @@
import androidx.ui.graphics.Image
import androidx.ui.layout.Column
import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.EdgeInsets
import androidx.ui.layout.Expanded
+import androidx.ui.layout.Gravity
import androidx.ui.layout.MainAxisAlignment
import androidx.ui.layout.Row
import androidx.ui.layout.Table
@@ -483,48 +483,49 @@
Column {
table()
Container(height = dataRowHeight, padding = cellSpacing) {
- Row(
- Expanded,
- mainAxisAlignment = MainAxisAlignment.End,
- crossAxisAlignment = CrossAxisAlignment.Center
- ) {
+ Row(Expanded, mainAxisAlignment = MainAxisAlignment.End) {
val pages = (rows.size - 1) / pagination.rowsPerPage + 1
val startRow = pagination.rowsPerPage * pagination.page
val endRow = (startRow + pagination.rowsPerPage).coerceAtMost(rows.size)
+ val modifier = Gravity.Center
// TODO(calintat): Replace this with a dropdown menu whose items are taken
// from availableRowsPerPage (filtered to those that are in the range
// 0 until rows.size). When an item is selected, it should invoke
// onRowsPerPageChange with the appropriate value.
- Text(text = "Rows per page: ${pagination.rowsPerPage}")
+ Text(text = "Rows per page: ${pagination.rowsPerPage}", modifier = modifier)
WidthSpacer(width = 32.dp)
- Text(text = "${startRow + 1}-$endRow of ${rows.size}")
+ Text(text = "${startRow + 1}-$endRow of ${rows.size}", modifier = modifier)
WidthSpacer(width = 32.dp)
// TODO(calintat): Replace this with an image button with chevron_left icon.
- Ripple(bounded = false) {
- Clickable(>
- val newPage = pagination.page - 1
- if (newPage >= 0)
- pagination.onPageChange.invoke(newPage)
- }) {
- Text(text = "Prev")
+ Container(modifier = modifier) {
+ Ripple(bounded = false) {
+ Clickable(>
+ val newPage = pagination.page - 1
+ if (newPage >= 0)
+ pagination.onPageChange.invoke(newPage)
+ }) {
+ Text(text = "Prev")
+ }
}
}
WidthSpacer(width = 24.dp)
// TODO(calintat): Replace this with an image button with chevron_right icon.
- Ripple(bounded = false) {
- Clickable(>
- val newPage = pagination.page + 1
- if (newPage < pages)
- pagination.onPageChange.invoke(newPage)
- }) {
- Text(text = "Next")
+ Container(modifier = modifier) {
+ Ripple(bounded = false) {
+ Clickable(>
+ val newPage = pagination.page + 1
+ if (newPage < pages)
+ pagination.onPageChange.invoke(newPage)
+ }) {
+ Text(text = "Next")
+ }
}
}
}
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt b/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt
index 8a84047..b049f8d 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt
@@ -260,7 +260,7 @@
) {
val minHeight = if (icon == null) MinHeight else MinHeightWithIcon
ConstrainedBox(constraints = DpConstraints(minHeight = minHeight)) {
- FlexRow(crossAxisAlignment = CrossAxisAlignment.Start) {
+ FlexRow {
inflexible {
if (icon != null) {
Container(
@@ -357,7 +357,7 @@
trailing: @Composable() (() -> Unit)?
) {
ConstrainedBox(constraints = DpConstraints(minHeight = MinHeight)) {
- FlexRow(crossAxisAlignment = CrossAxisAlignment.Start) {
+ FlexRow {
inflexible {
if (icon != null) {
Container(
diff --git a/ui/ui-platform/api/0.1.0-dev03.txt b/ui/ui-platform/api/0.1.0-dev03.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/0.1.0-dev03.txt
+++ b/ui/ui-platform/api/0.1.0-dev03.txt
@@ -23,9 +23,11 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
method public androidx.ui.core.Constraints getConstraints();
method public androidx.ui.core.Density getDensity();
+ method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
method public long getMeasureIteration();
method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
method public androidx.ui.core.LayoutNode getRoot();
+ method public androidx.ui.input.TextInputService getTextInputService();
method public void onAttach(androidx.ui.core.ComponentNode node);
method public void onDetach(androidx.ui.core.ComponentNode node);
method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
property public final androidx.ui.core.Constraints constraints;
property public androidx.ui.core.Density density;
+ property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
property public long measureIteration;
property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
property public final androidx.ui.core.LayoutNode root;
+ property public final androidx.ui.input.TextInputService textInputService;
}
public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/current.txt b/ui/ui-platform/api/current.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/current.txt
+++ b/ui/ui-platform/api/current.txt
@@ -23,9 +23,11 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
method public androidx.ui.core.Constraints getConstraints();
method public androidx.ui.core.Density getDensity();
+ method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
method public long getMeasureIteration();
method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
method public androidx.ui.core.LayoutNode getRoot();
+ method public androidx.ui.input.TextInputService getTextInputService();
method public void onAttach(androidx.ui.core.ComponentNode node);
method public void onDetach(androidx.ui.core.ComponentNode node);
method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
property public final androidx.ui.core.Constraints constraints;
property public androidx.ui.core.Density density;
+ property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
property public long measureIteration;
property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
property public final androidx.ui.core.LayoutNode root;
+ property public final androidx.ui.input.TextInputService textInputService;
}
public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt
@@ -23,9 +23,11 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
method public androidx.ui.core.Constraints getConstraints();
method public androidx.ui.core.Density getDensity();
+ method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
method public long getMeasureIteration();
method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
method public androidx.ui.core.LayoutNode getRoot();
+ method public androidx.ui.input.TextInputService getTextInputService();
method public void onAttach(androidx.ui.core.ComponentNode node);
method public void onDetach(androidx.ui.core.ComponentNode node);
method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
property public final androidx.ui.core.Constraints constraints;
property public androidx.ui.core.Density density;
+ property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
property public long measureIteration;
property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
property public final androidx.ui.core.LayoutNode root;
+ property public final androidx.ui.input.TextInputService textInputService;
}
public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/public_plus_experimental_current.txt b/ui/ui-platform/api/public_plus_experimental_current.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/public_plus_experimental_current.txt
+++ b/ui/ui-platform/api/public_plus_experimental_current.txt
@@ -23,9 +23,11 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
method public androidx.ui.core.Constraints getConstraints();
method public androidx.ui.core.Density getDensity();
+ method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
method public long getMeasureIteration();
method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
method public androidx.ui.core.LayoutNode getRoot();
+ method public androidx.ui.input.TextInputService getTextInputService();
method public void onAttach(androidx.ui.core.ComponentNode node);
method public void onDetach(androidx.ui.core.ComponentNode node);
method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
property public final androidx.ui.core.Constraints constraints;
property public androidx.ui.core.Density density;
+ property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
property public long measureIteration;
property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
property public final androidx.ui.core.LayoutNode root;
+ property public final androidx.ui.input.TextInputService textInputService;
}
public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/restricted_0.1.0-dev03.txt b/ui/ui-platform/api/restricted_0.1.0-dev03.txt
index 6e0e953..7cdc759 100644
--- a/ui/ui-platform/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-platform/api/restricted_0.1.0-dev03.txt
@@ -23,9 +23,11 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
method public androidx.ui.core.Constraints getConstraints();
method public androidx.ui.core.Density getDensity();
+ method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
method public long getMeasureIteration();
method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
method public androidx.ui.core.LayoutNode getRoot();
+ method public androidx.ui.input.TextInputService getTextInputService();
method public void onAttach(androidx.ui.core.ComponentNode node);
method public void onDetach(androidx.ui.core.ComponentNode node);
method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
property public final androidx.ui.core.Constraints constraints;
property public androidx.ui.core.Density density;
+ property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
property public long measureIteration;
property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
property public final androidx.ui.core.LayoutNode root;
+ property public final androidx.ui.input.TextInputService textInputService;
}
public final class AndroidOwnerKt {
@@ -439,15 +443,6 @@
}
-package androidx.ui.core.text {
-
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class AndroidFontResourceLoader implements androidx.ui.text.font.Font.ResourceLoader {
- ctor public AndroidFontResourceLoader(android.content.Context context);
- method public android.graphics.Typeface load(androidx.ui.text.font.Font font);
- }
-
-}
-
package androidx.ui.input {
public final class InputStateKt {
diff --git a/ui/ui-platform/api/restricted_current.txt b/ui/ui-platform/api/restricted_current.txt
index 6e0e953..7cdc759 100644
--- a/ui/ui-platform/api/restricted_current.txt
+++ b/ui/ui-platform/api/restricted_current.txt
@@ -23,9 +23,11 @@
method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
method public androidx.ui.core.Constraints getConstraints();
method public androidx.ui.core.Density getDensity();
+ method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
method public long getMeasureIteration();
method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
method public androidx.ui.core.LayoutNode getRoot();
+ method public androidx.ui.input.TextInputService getTextInputService();
method public void onAttach(androidx.ui.core.ComponentNode node);
method public void onDetach(androidx.ui.core.ComponentNode node);
method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
property public final androidx.ui.core.Constraints constraints;
property public androidx.ui.core.Density density;
+ property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
property public long measureIteration;
property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
property public final androidx.ui.core.LayoutNode root;
+ property public final androidx.ui.input.TextInputService textInputService;
}
public final class AndroidOwnerKt {
@@ -439,15 +443,6 @@
}
-package androidx.ui.core.text {
-
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class AndroidFontResourceLoader implements androidx.ui.text.font.Font.ResourceLoader {
- ctor public AndroidFontResourceLoader(android.content.Context context);
- method public android.graphics.Typeface load(androidx.ui.text.font.Font font);
- }
-
-}
-
package androidx.ui.input {
public final class InputStateKt {
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
index 4d41ff0..5f4ea2b 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
@@ -31,19 +31,6 @@
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import androidx.annotation.RequiresApi
-import androidx.annotation.RestrictTo
-import androidx.ui.input.TextInputServiceAndroid
-import androidx.ui.core.pointerinput.PointerInputEventProcessor
-import androidx.ui.core.pointerinput.toPointerInputEvent
-import androidx.ui.engine.geometry.Outline
-import androidx.ui.input.TextInputService
-import androidx.ui.graphics.Canvas
-import androidx.ui.graphics.Path
-import androidx.ui.engine.geometry.Rect
-import androidx.ui.engine.geometry.RRect
-import androidx.ui.engine.geometry.Shape
-import kotlin.math.roundToInt
-import java.util.TreeSet
import androidx.compose.trace
import androidx.ui.autofill.AndroidAutofill
import androidx.ui.autofill.Autofill
@@ -53,6 +40,20 @@
import androidx.ui.autofill.registerCallback
import androidx.ui.autofill.unregisterCallback
import androidx.ui.core.NodeStagesModelObserver.Stage
+import androidx.ui.core.pointerinput.PointerInputEventProcessor
+import androidx.ui.core.pointerinput.toPointerInputEvent
+import androidx.ui.core.text.AndroidFontResourceLoader
+import androidx.ui.engine.geometry.Outline
+import androidx.ui.engine.geometry.RRect
+import androidx.ui.engine.geometry.Rect
+import androidx.ui.engine.geometry.Shape
+import androidx.ui.graphics.Canvas
+import androidx.ui.graphics.Path
+import androidx.ui.input.TextInputServiceAndroid
+import androidx.ui.input.TextInputService
+import androidx.ui.text.font.Font
+import java.util.TreeSet
+import kotlin.math.roundToInt
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class AndroidComposeView constructor(context: Context) :
@@ -580,10 +581,10 @@
private val textInputServiceAndroid = TextInputServiceAndroid(this)
- /** @hide */
- @RestrictTo(RestrictTo.Scope.LIBRARY)
val textInputService = TextInputService(textInputServiceAndroid)
+ val fontLoader: Font.ResourceLoader = AndroidFontResourceLoader(context)
+
override fun onCheckIsTextEditor(): Boolean = textInputServiceAndroid.isEditorFocused()
override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? =
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt b/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt
index c5126a7..c26427e 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt
@@ -18,17 +18,13 @@
import android.content.Context
import android.graphics.Typeface
-import androidx.annotation.RestrictTo
import androidx.core.content.res.ResourcesCompat
import androidx.ui.text.font.Font
/**
* Android implementation for [Font.ResourceLoader]
- *
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class AndroidFontResourceLoader(private val context: Context) : Font.ResourceLoader {
+internal class AndroidFontResourceLoader(private val context: Context) : Font.ResourceLoader {
override fun load(font: Font): Typeface {
val resId = context.resources.getIdentifier(
font.name.substringBefore("."),
diff --git a/ui/ui-text/api/0.1.0-dev03.txt b/ui/ui-text/api/0.1.0-dev03.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/0.1.0-dev03.txt
+++ b/ui/ui-text/api/0.1.0-dev03.txt
@@ -1,6 +1,55 @@
// Signature format: 3.0
package androidx.ui.input {
+ public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+ ctor public BackspaceKeyEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public CommitTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public interface EditOperation {
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class EditingBuffer {
+ ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+ field public static final int NOWHERE = -1; // 0xffffffff
+ }
+
+ public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public FinishComposingTextEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public enum ImeAction {
enum_constant public static final androidx.ui.input.ImeAction Done;
enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
enum_constant public static final androidx.ui.input.ImeAction Unspecified;
}
+ public interface InputEventListener {
+ method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+ method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+ }
+
+ public final class InputState {
+ ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ ctor public InputState();
+ method public String component1();
+ method public androidx.ui.text.TextRange component2();
+ method public androidx.ui.text.TextRange? component3();
+ method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ method public androidx.ui.text.TextRange? getComposition();
+ method public String getSelectedText();
+ method public androidx.ui.text.TextRange getSelection();
+ method public String getText();
+ method public String getTextAfterSelection(int maxChars);
+ method public String getTextBeforeSelection(int maxChars);
+ }
+
public enum KeyboardType {
enum_constant public static final androidx.ui.input.KeyboardType Ascii;
enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
enum_constant public static final androidx.ui.input.KeyboardType Uri;
}
+ public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+ ctor public MoveCursorEditOp(int amount);
+ method public int component1();
+ method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+ method public int getAmount();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public interface OffsetMap {
method public int originalToTransformed(int offset);
method public int transformedToOriginal(int offset);
+ field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+ }
+
+ public static final class OffsetMap.Companion {
+ method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+ property public final androidx.ui.input.OffsetMap identityOffsetMap;
}
public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
method public char getMask();
}
+ public interface PlatformTextInputService {
+ method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard();
+ method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput();
+ }
+
+ public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingRegionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetSelectionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public class TextInputService {
+ ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+ method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard(int token);
+ method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput(int token);
+ }
+
public final class TextInputServiceKt {
ctor public TextInputServiceKt();
+ field public static final int INVALID_SESSION = -1; // 0xffffffff
+ field public static final int NO_SESSION = 0; // 0x0
}
public final class TransformedText {
@@ -52,10 +184,6 @@
method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
}
- public final class VisualTransformationKt {
- ctor public VisualTransformationKt();
- }
-
}
package androidx.ui.text {
@@ -322,8 +450,17 @@
method public static String substring(CharSequence, androidx.ui.text.TextRange range);
}
+ public final class TextSpan {
+ ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+ ctor public TextSpan();
+ method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+ method public androidx.ui.text.TextStyle? getStyle();
+ method public String? getText();
+ }
+
public final class TextSpanKt {
ctor public TextSpanKt();
+ method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
}
public final class TextStyle {
@@ -365,7 +502,7 @@
public final class TextStyleKt {
ctor public TextStyleKt();
- method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+ method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
}
}
@@ -472,7 +609,7 @@
public final class FontWeightKt {
ctor public FontWeightKt();
- method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+ method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
}
}
diff --git a/ui/ui-text/api/api_lint.ignore b/ui/ui-text/api/api_lint.ignore
index 8d871e2..9671a85 100644
--- a/ui/ui-text/api/api_lint.ignore
+++ b/ui/ui-text/api/api_lint.ignore
@@ -45,6 +45,8 @@
Missing `build()` method in androidx.ui.text.AnnotatedString.Builder
+MissingNullability: androidx.ui.input.OffsetMap#Companion:
+ Missing nullability on field `Companion` in class `class androidx.ui.input.OffsetMap`
MissingNullability: androidx.ui.text.Locale#Companion:
Missing nullability on field `Companion` in class `class androidx.ui.text.Locale`
MissingNullability: androidx.ui.text.LocaleList#Companion:
diff --git a/ui/ui-text/api/current.txt b/ui/ui-text/api/current.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/current.txt
+++ b/ui/ui-text/api/current.txt
@@ -1,6 +1,55 @@
// Signature format: 3.0
package androidx.ui.input {
+ public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+ ctor public BackspaceKeyEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public CommitTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public interface EditOperation {
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class EditingBuffer {
+ ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+ field public static final int NOWHERE = -1; // 0xffffffff
+ }
+
+ public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public FinishComposingTextEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public enum ImeAction {
enum_constant public static final androidx.ui.input.ImeAction Done;
enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
enum_constant public static final androidx.ui.input.ImeAction Unspecified;
}
+ public interface InputEventListener {
+ method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+ method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+ }
+
+ public final class InputState {
+ ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ ctor public InputState();
+ method public String component1();
+ method public androidx.ui.text.TextRange component2();
+ method public androidx.ui.text.TextRange? component3();
+ method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ method public androidx.ui.text.TextRange? getComposition();
+ method public String getSelectedText();
+ method public androidx.ui.text.TextRange getSelection();
+ method public String getText();
+ method public String getTextAfterSelection(int maxChars);
+ method public String getTextBeforeSelection(int maxChars);
+ }
+
public enum KeyboardType {
enum_constant public static final androidx.ui.input.KeyboardType Ascii;
enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
enum_constant public static final androidx.ui.input.KeyboardType Uri;
}
+ public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+ ctor public MoveCursorEditOp(int amount);
+ method public int component1();
+ method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+ method public int getAmount();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public interface OffsetMap {
method public int originalToTransformed(int offset);
method public int transformedToOriginal(int offset);
+ field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+ }
+
+ public static final class OffsetMap.Companion {
+ method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+ property public final androidx.ui.input.OffsetMap identityOffsetMap;
}
public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
method public char getMask();
}
+ public interface PlatformTextInputService {
+ method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard();
+ method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput();
+ }
+
+ public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingRegionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetSelectionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public class TextInputService {
+ ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+ method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard(int token);
+ method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput(int token);
+ }
+
public final class TextInputServiceKt {
ctor public TextInputServiceKt();
+ field public static final int INVALID_SESSION = -1; // 0xffffffff
+ field public static final int NO_SESSION = 0; // 0x0
}
public final class TransformedText {
@@ -52,10 +184,6 @@
method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
}
- public final class VisualTransformationKt {
- ctor public VisualTransformationKt();
- }
-
}
package androidx.ui.text {
@@ -322,8 +450,17 @@
method public static String substring(CharSequence, androidx.ui.text.TextRange range);
}
+ public final class TextSpan {
+ ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+ ctor public TextSpan();
+ method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+ method public androidx.ui.text.TextStyle? getStyle();
+ method public String? getText();
+ }
+
public final class TextSpanKt {
ctor public TextSpanKt();
+ method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
}
public final class TextStyle {
@@ -365,7 +502,7 @@
public final class TextStyleKt {
ctor public TextStyleKt();
- method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+ method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
}
}
@@ -472,7 +609,7 @@
public final class FontWeightKt {
ctor public FontWeightKt();
- method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+ method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
}
}
diff --git a/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt
@@ -1,6 +1,55 @@
// Signature format: 3.0
package androidx.ui.input {
+ public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+ ctor public BackspaceKeyEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public CommitTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public interface EditOperation {
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class EditingBuffer {
+ ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+ field public static final int NOWHERE = -1; // 0xffffffff
+ }
+
+ public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public FinishComposingTextEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public enum ImeAction {
enum_constant public static final androidx.ui.input.ImeAction Done;
enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
enum_constant public static final androidx.ui.input.ImeAction Unspecified;
}
+ public interface InputEventListener {
+ method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+ method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+ }
+
+ public final class InputState {
+ ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ ctor public InputState();
+ method public String component1();
+ method public androidx.ui.text.TextRange component2();
+ method public androidx.ui.text.TextRange? component3();
+ method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ method public androidx.ui.text.TextRange? getComposition();
+ method public String getSelectedText();
+ method public androidx.ui.text.TextRange getSelection();
+ method public String getText();
+ method public String getTextAfterSelection(int maxChars);
+ method public String getTextBeforeSelection(int maxChars);
+ }
+
public enum KeyboardType {
enum_constant public static final androidx.ui.input.KeyboardType Ascii;
enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
enum_constant public static final androidx.ui.input.KeyboardType Uri;
}
+ public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+ ctor public MoveCursorEditOp(int amount);
+ method public int component1();
+ method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+ method public int getAmount();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public interface OffsetMap {
method public int originalToTransformed(int offset);
method public int transformedToOriginal(int offset);
+ field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+ }
+
+ public static final class OffsetMap.Companion {
+ method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+ property public final androidx.ui.input.OffsetMap identityOffsetMap;
}
public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
method public char getMask();
}
+ public interface PlatformTextInputService {
+ method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard();
+ method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput();
+ }
+
+ public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingRegionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetSelectionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public class TextInputService {
+ ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+ method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard(int token);
+ method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput(int token);
+ }
+
public final class TextInputServiceKt {
ctor public TextInputServiceKt();
+ field public static final int INVALID_SESSION = -1; // 0xffffffff
+ field public static final int NO_SESSION = 0; // 0x0
}
public final class TransformedText {
@@ -52,10 +184,6 @@
method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
}
- public final class VisualTransformationKt {
- ctor public VisualTransformationKt();
- }
-
}
package androidx.ui.text {
@@ -322,8 +450,17 @@
method public static String substring(CharSequence, androidx.ui.text.TextRange range);
}
+ public final class TextSpan {
+ ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+ ctor public TextSpan();
+ method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+ method public androidx.ui.text.TextStyle? getStyle();
+ method public String? getText();
+ }
+
public final class TextSpanKt {
ctor public TextSpanKt();
+ method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
}
public final class TextStyle {
@@ -365,7 +502,7 @@
public final class TextStyleKt {
ctor public TextStyleKt();
- method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+ method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
}
}
@@ -472,7 +609,7 @@
public final class FontWeightKt {
ctor public FontWeightKt();
- method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+ method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
}
}
diff --git a/ui/ui-text/api/public_plus_experimental_current.txt b/ui/ui-text/api/public_plus_experimental_current.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/ui/ui-text/api/public_plus_experimental_current.txt
@@ -1,6 +1,55 @@
// Signature format: 3.0
package androidx.ui.input {
+ public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+ ctor public BackspaceKeyEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public CommitTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public interface EditOperation {
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class EditingBuffer {
+ ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+ field public static final int NOWHERE = -1; // 0xffffffff
+ }
+
+ public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public FinishComposingTextEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public enum ImeAction {
enum_constant public static final androidx.ui.input.ImeAction Done;
enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
enum_constant public static final androidx.ui.input.ImeAction Unspecified;
}
+ public interface InputEventListener {
+ method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+ method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+ }
+
+ public final class InputState {
+ ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ ctor public InputState();
+ method public String component1();
+ method public androidx.ui.text.TextRange component2();
+ method public androidx.ui.text.TextRange? component3();
+ method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ method public androidx.ui.text.TextRange? getComposition();
+ method public String getSelectedText();
+ method public androidx.ui.text.TextRange getSelection();
+ method public String getText();
+ method public String getTextAfterSelection(int maxChars);
+ method public String getTextBeforeSelection(int maxChars);
+ }
+
public enum KeyboardType {
enum_constant public static final androidx.ui.input.KeyboardType Ascii;
enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
enum_constant public static final androidx.ui.input.KeyboardType Uri;
}
+ public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+ ctor public MoveCursorEditOp(int amount);
+ method public int component1();
+ method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+ method public int getAmount();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
public interface OffsetMap {
method public int originalToTransformed(int offset);
method public int transformedToOriginal(int offset);
+ field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+ }
+
+ public static final class OffsetMap.Companion {
+ method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+ property public final androidx.ui.input.OffsetMap identityOffsetMap;
}
public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
method public char getMask();
}
+ public interface PlatformTextInputService {
+ method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard();
+ method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput();
+ }
+
+ public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingRegionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetSelectionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public class TextInputService {
+ ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+ method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard(int token);
+ method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput(int token);
+ }
+
public final class TextInputServiceKt {
ctor public TextInputServiceKt();
+ field public static final int INVALID_SESSION = -1; // 0xffffffff
+ field public static final int NO_SESSION = 0; // 0x0
}
public final class TransformedText {
@@ -52,10 +184,6 @@
method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
}
- public final class VisualTransformationKt {
- ctor public VisualTransformationKt();
- }
-
}
package androidx.ui.text {
@@ -322,8 +450,17 @@
method public static String substring(CharSequence, androidx.ui.text.TextRange range);
}
+ public final class TextSpan {
+ ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+ ctor public TextSpan();
+ method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+ method public androidx.ui.text.TextStyle? getStyle();
+ method public String? getText();
+ }
+
public final class TextSpanKt {
ctor public TextSpanKt();
+ method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
}
public final class TextStyle {
@@ -365,7 +502,7 @@
public final class TextStyleKt {
ctor public TextStyleKt();
- method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+ method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
}
}
@@ -472,7 +609,7 @@
public final class FontWeightKt {
ctor public FontWeightKt();
- method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+ method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
}
}
diff --git a/ui/ui-text/api/restricted_0.1.0-dev03.txt b/ui/ui-text/api/restricted_0.1.0-dev03.txt
index 311a121..5157e30 100644
--- a/ui/ui-text/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-text/api/restricted_0.1.0-dev03.txt
@@ -1,13 +1,55 @@
// Signature format: 3.0
package androidx.ui.input {
+ public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+ ctor public BackspaceKeyEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public CommitTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public interface EditOperation {
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public final class EditingBuffer {
+ ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+ field public static final int NOWHERE = -1; // 0xffffffff
+ }
-
-
-
-
+ public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public FinishComposingTextEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
public enum ImeAction {
enum_constant public static final androidx.ui.input.ImeAction Done;
@@ -20,7 +62,25 @@
enum_constant public static final androidx.ui.input.ImeAction Unspecified;
}
+ public interface InputEventListener {
+ method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+ method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+ }
+ public final class InputState {
+ ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ ctor public InputState();
+ method public String component1();
+ method public androidx.ui.text.TextRange component2();
+ method public androidx.ui.text.TextRange? component3();
+ method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ method public androidx.ui.text.TextRange? getComposition();
+ method public String getSelectedText();
+ method public androidx.ui.text.TextRange getSelection();
+ method public String getText();
+ method public String getTextAfterSelection(int maxChars);
+ method public String getTextBeforeSelection(int maxChars);
+ }
public enum KeyboardType {
enum_constant public static final androidx.ui.input.KeyboardType Ascii;
@@ -33,10 +93,23 @@
enum_constant public static final androidx.ui.input.KeyboardType Uri;
}
+ public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+ ctor public MoveCursorEditOp(int amount);
+ method public int component1();
+ method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+ method public int getAmount();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
public interface OffsetMap {
method public int originalToTransformed(int offset);
method public int transformedToOriginal(int offset);
+ field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+ }
+
+ public static final class OffsetMap.Companion {
+ method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+ property public final androidx.ui.input.OffsetMap identityOffsetMap;
}
@@ -47,13 +120,57 @@
method public char getMask();
}
+ public interface PlatformTextInputService {
+ method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard();
+ method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput();
+ }
+ public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingRegionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetSelectionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public class TextInputService {
+ ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+ method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard(int token);
+ method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput(int token);
+ }
public final class TextInputServiceKt {
ctor public TextInputServiceKt();
+ field public static final int INVALID_SESSION = -1; // 0xffffffff
+ field public static final int NO_SESSION = 0; // 0x0
}
public final class TransformedText {
@@ -69,10 +186,6 @@
method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
}
- public final class VisualTransformationKt {
- ctor public VisualTransformationKt();
- }
-
}
package androidx.ui.text {
@@ -340,18 +453,17 @@
method public static String substring(CharSequence, androidx.ui.text.TextRange range);
}
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class TextSpan {
+ public final class TextSpan {
ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
ctor public TextSpan();
method public java.util.List<androidx.ui.text.TextSpan> getChildren();
method public androidx.ui.text.TextStyle? getStyle();
method public String? getText();
- method public boolean visitTextSpan(kotlin.jvm.functions.Function1<? super androidx.ui.text.TextSpan,java.lang.Boolean> visitor);
}
public final class TextSpanKt {
ctor public TextSpanKt();
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
+ method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
}
public final class TextStyle {
@@ -393,7 +505,7 @@
public final class TextStyleKt {
ctor public TextStyleKt();
- method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+ method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
}
}
@@ -500,7 +612,7 @@
public final class FontWeightKt {
ctor public FontWeightKt();
- method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+ method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
}
}
diff --git a/ui/ui-text/api/restricted_current.txt b/ui/ui-text/api/restricted_current.txt
index 311a121..5157e30 100644
--- a/ui/ui-text/api/restricted_current.txt
+++ b/ui/ui-text/api/restricted_current.txt
@@ -1,13 +1,55 @@
// Signature format: 3.0
package androidx.ui.input {
+ public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+ ctor public BackspaceKeyEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public CommitTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+ ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+ method public int getAfterLength();
+ method public int getBeforeLength();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+
+ public interface EditOperation {
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public final class EditingBuffer {
+ ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+ field public static final int NOWHERE = -1; // 0xffffffff
+ }
-
-
-
-
+ public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public FinishComposingTextEditOp();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
public enum ImeAction {
enum_constant public static final androidx.ui.input.ImeAction Done;
@@ -20,7 +62,25 @@
enum_constant public static final androidx.ui.input.ImeAction Unspecified;
}
+ public interface InputEventListener {
+ method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+ method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+ }
+ public final class InputState {
+ ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ ctor public InputState();
+ method public String component1();
+ method public androidx.ui.text.TextRange component2();
+ method public androidx.ui.text.TextRange? component3();
+ method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+ method public androidx.ui.text.TextRange? getComposition();
+ method public String getSelectedText();
+ method public androidx.ui.text.TextRange getSelection();
+ method public String getText();
+ method public String getTextAfterSelection(int maxChars);
+ method public String getTextBeforeSelection(int maxChars);
+ }
public enum KeyboardType {
enum_constant public static final androidx.ui.input.KeyboardType Ascii;
@@ -33,10 +93,23 @@
enum_constant public static final androidx.ui.input.KeyboardType Uri;
}
+ public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+ ctor public MoveCursorEditOp(int amount);
+ method public int component1();
+ method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+ method public int getAmount();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
public interface OffsetMap {
method public int originalToTransformed(int offset);
method public int transformedToOriginal(int offset);
+ field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+ }
+
+ public static final class OffsetMap.Companion {
+ method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+ property public final androidx.ui.input.OffsetMap identityOffsetMap;
}
@@ -47,13 +120,57 @@
method public char getMask();
}
+ public interface PlatformTextInputService {
+ method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard();
+ method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput();
+ }
+ public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingRegionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+ method public String component1();
+ method public int component2();
+ method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+ method public int getNewCursorPosition();
+ method public String getText();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+ ctor public SetSelectionEditOp(int start, int end);
+ method public int component1();
+ method public int component2();
+ method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+ method public int getEnd();
+ method public int getStart();
+ method public void process(androidx.ui.input.EditingBuffer buffer);
+ }
+ public class TextInputService {
+ ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+ method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+ method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+ method public void showSoftwareKeyboard(int token);
+ method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void stopInput(int token);
+ }
public final class TextInputServiceKt {
ctor public TextInputServiceKt();
+ field public static final int INVALID_SESSION = -1; // 0xffffffff
+ field public static final int NO_SESSION = 0; // 0x0
}
public final class TransformedText {
@@ -69,10 +186,6 @@
method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
}
- public final class VisualTransformationKt {
- ctor public VisualTransformationKt();
- }
-
}
package androidx.ui.text {
@@ -340,18 +453,17 @@
method public static String substring(CharSequence, androidx.ui.text.TextRange range);
}
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class TextSpan {
+ public final class TextSpan {
ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
ctor public TextSpan();
method public java.util.List<androidx.ui.text.TextSpan> getChildren();
method public androidx.ui.text.TextStyle? getStyle();
method public String? getText();
- method public boolean visitTextSpan(kotlin.jvm.functions.Function1<? super androidx.ui.text.TextSpan,java.lang.Boolean> visitor);
}
public final class TextSpanKt {
ctor public TextSpanKt();
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
+ method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
}
public final class TextStyle {
@@ -393,7 +505,7 @@
public final class TextStyleKt {
ctor public TextStyleKt();
- method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+ method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
}
}
@@ -500,7 +612,7 @@
public final class FontWeightKt {
ctor public FontWeightKt();
- method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+ method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
}
}
diff --git a/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt b/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt
index 52c5388..e25e640 100644
--- a/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt
+++ b/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt
@@ -19,7 +19,6 @@
import androidx.annotation.Sampled
import androidx.ui.input.OffsetMap
import androidx.ui.input.TransformedText
-import androidx.ui.input.identityOffsetMap
import androidx.ui.text.AnnotatedString
@Sampled
@@ -28,10 +27,10 @@
AnnotatedString("*".repeat(text.text.length)),
/**
- * identityOffsetMap is a predefined [OffsetMap] that can be used for the transformation
- * that does not change the character count.
+ * [OffsetMap.identityOffsetMap] is a predefined [OffsetMap] that can be used for the
+ * transformation that does not change the character count.
*/
- identityOffsetMap
+ OffsetMap.identityOffsetMap
)
}
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt
index c55e8dc..7d0f2b1 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt
@@ -23,7 +23,6 @@
import androidx.ui.input.ImeAction
import androidx.ui.input.KeyboardType
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.foundation.VerticalScroller
import androidx.ui.layout.ExpandedHeight
import androidx.ui.text.TextStyle
@@ -52,10 +51,7 @@
@Composable
fun InputFieldDemo() {
VerticalScroller {
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(ExpandedHeight) {
TagLine(tag = "simple editing")
EditLine()
TagLine(tag = "simple editing2")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt
index 8e3ef59..0cf4ff6 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt
@@ -24,7 +24,6 @@
import androidx.ui.core.TextField
import androidx.ui.core.sp
import androidx.ui.foundation.VerticalScroller
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.graphics.Color
import androidx.ui.input.ImeAction
import androidx.ui.layout.Column
@@ -33,7 +32,7 @@
@Composable
fun TextFieldFocusTransition() {
VerticalScroller {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
TextFieldWithFocusId("Focus 1", "Focus 2")
TextFieldWithFocusId("Focus 2", "Focus 3")
TextFieldWithFocusId("Focus 3", "Focus 4")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt
index f33a865..eef0d12 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt
@@ -22,7 +22,6 @@
import androidx.ui.core.TextField
import androidx.ui.core.sp
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.foundation.VerticalScroller
import androidx.ui.input.KeyboardType
import androidx.ui.text.TextStyle
@@ -30,7 +29,7 @@
@Composable
fun InputFieldTrickyUseCase() {
VerticalScroller {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
TagLine(tag = "don't set if non number is added")
RejectNonDigits()
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt
index 124c2ef..41d4b7f 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt
@@ -21,7 +21,6 @@
import androidx.ui.core.sp
import androidx.ui.foundation.VerticalScroller
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.text.AnnotatedString
import androidx.ui.text.ParagraphStyle
import androidx.ui.text.TextStyle
@@ -35,7 +34,7 @@
@Composable
fun MultiParagraphDemo() {
VerticalScroller {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
TagLine(tag = "multiple paragraphs basic")
TextDemoParagraph()
TagLine(tag = "multiple paragraphs TextAlign")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt
index b9ebe14..4ef4b51 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt
@@ -28,7 +28,6 @@
import androidx.ui.graphics.Color
import androidx.ui.graphics.lerp
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.Row
import androidx.ui.foundation.VerticalScroller
import androidx.ui.text.ParagraphStyle
@@ -65,7 +64,7 @@
@Composable
fun TextDemo() {
VerticalScroller {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
TagLine(tag = "color, fontSize, fontWeight and fontStyle")
TextDemoBasic()
TagLine(tag = "color, fontSize, fontWeight, fontFamily, fontStyle, letterSpacing, " +
@@ -369,10 +368,7 @@
for (i in 1..10) {
text = "$text$displayText "
}
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(ExpandedHeight) {
SecondTagLine(tag = "textAlign = TextAlign.Left")
Text(paragraphStyle = ParagraphStyle(textAlign = TextAlign.Left)) {
Span(text = displayText, style = TextStyle(fontSize = fontSize8))
@@ -441,10 +437,7 @@
val textStyle =
TextStyle(fontSize = fontSize8, color = Color(0xFFFF0000))
- Column(
- ExpandedHeight,
- crossAxisAlignment = CrossAxisAlignment.Start
- ) {
+ Column(ExpandedHeight) {
Text {
Span(text = text, style = textStyle)
}
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt
index 4c815f4..8104626 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt
@@ -27,7 +27,6 @@
import androidx.ui.foundation.text.SelectionContainer
import androidx.ui.graphics.Color
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.ExpandedHeight
import androidx.ui.layout.ExpandedWidth
import androidx.ui.layout.Row
@@ -39,7 +38,7 @@
@Composable
fun TextSelectionDemo() {
VerticalScroller {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
TagLine(tag = "selection")
TextDemoSelection()
TagLine(tag = "selection with string input")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt
index 42c5fe7..9400fb1 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt
@@ -33,7 +33,6 @@
import androidx.ui.foundation.text.SelectionContainer
import androidx.ui.graphics.Color
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.layout.FlexRow
import androidx.ui.layout.Padding
import androidx.ui.text.AnnotatedString
@@ -90,7 +89,7 @@
selection.value = it }
) {
Padding(12.dp) {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
Basics()
AddTextElement()
langContent.forEach {
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt
index 763c5f4..8f7e43a 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt
@@ -31,7 +31,6 @@
import androidx.ui.input.ImeAction
import androidx.ui.input.KeyboardType
import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
import androidx.ui.foundation.VerticalScroller
import androidx.ui.text.AnnotatedString
import androidx.ui.text.LocaleList
@@ -173,7 +172,7 @@
@Composable
fun VariousInputFieldDemo() {
VerticalScroller {
- Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+ Column {
TagLine(tag = "Capitalization")
VariousEditLine(
keyboardType = KeyboardType.Ascii,
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt b/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt
index bf88c34..2e66b46 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt
@@ -16,20 +16,17 @@
package androidx.ui.input
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY
import java.text.BreakIterator
import java.util.Objects
+import kotlin.math.max
+import kotlin.math.min
/**
* A base class of all EditOperations
*
* An EditOperation is a representation of platform IME API call. For example, in Android,
* InputConnection#commitText API call is translated to CommitTextEditOp object.
- *
- * @hide
*/
-@RestrictTo(LIBRARY)
interface EditOperation {
/**
@@ -41,11 +38,8 @@
/**
* An edit operation represent commitText callback from InputMethod.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#commitText(java.lang.CharSequence,%20int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#commitText(java.lang.CharSequence,%20int)>
*/
-@RestrictTo(LIBRARY)
data class CommitTextEditOp(
/**
* The text to commit. We ignore any styles in the original API.
@@ -87,11 +81,8 @@
/**
* An edit operation represents setComposingRegion callback from InputMethod.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingRegion(int,%2520int)
-
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingRegion(int,%2520int)>
*/
-@RestrictTo(LIBRARY)
data class SetComposingRegionEditOp(
/**
* The inclusive start offset of the composing region.
@@ -126,11 +117,8 @@
/**
* An edit operation represents setComposingText callback from InputMethod
*
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingText(java.lang.CharSequence,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingText(java.lang.CharSequence,%2520int)>
*/
-@RestrictTo(LIBRARY)
data class SetComposingTextEditOp(
/**
* The composing text.
@@ -178,11 +166,8 @@
/**
* An edit operation represents deleteSurroundingText callback from InputMethod
*
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingText(int,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingText(int,%2520int)>
*/
-@RestrictTo(LIBRARY)
data class DeleteSurroundingTextEditOp(
/**
* The number of characters in UTF-16 before the cursor to be deleted.
@@ -196,11 +181,11 @@
override fun process(buffer: EditingBuffer) {
buffer.delete(
buffer.selectionEnd,
- Math.min(buffer.selectionEnd + afterLength, buffer.length)
+ min(buffer.selectionEnd + afterLength, buffer.length)
)
buffer.delete(
- Math.max(0, buffer.selectionStart - beforeLength),
+ max(0, buffer.selectionStart - beforeLength),
buffer.selectionStart
)
}
@@ -208,11 +193,8 @@
/**
* An edit operation represents deleteSurroundingTextInCodePoitns callback from InputMethod
*
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingTextInCodePoints(int,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingTextInCodePoints(int,%2520int)>
*/
-@RestrictTo(LIBRARY)
data class DeleteSurroundingTextInCodePointsEditOp(
/**
* The number of characters in Unicode code points before the cursor to be deleted.
@@ -261,11 +243,8 @@
/**
* An edit operation represents setSelection callback from InputMethod
*
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setSelection(int,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setSelection(int,%2520int)>
*/
-@RestrictTo(LIBRARY)
data class SetSelectionEditOp(
/**
* The inclusive start offset of the selection region.
@@ -291,11 +270,8 @@
/**
* An edit operation represents finishComposingText callback from InputMEthod
*
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#finishComposingText()
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#finishComposingText()>
*/
-@RestrictTo(LIBRARY)
class FinishComposingTextEditOp : EditOperation {
override fun process(buffer: EditingBuffer) {
@@ -314,10 +290,7 @@
* If there is composition, delete the text in the composition range.
* If there is no composition but there is selection, delete whole selected range.
* If there is no composition and selection, perform backspace key event at the cursor position.
- *
- * @hide
*/
-@RestrictTo(LIBRARY)
class BackspaceKeyEditOp : EditOperation {
override fun process(buffer: EditingBuffer) {
@@ -355,10 +328,7 @@
*
* If there is selection, cancel the selection first and move the cursor to the selection start
* position. Then perform the cursor movement.
- *
- * @hide
*/
-@RestrictTo(LIBRARY)
data class MoveCursorEditOp(
/**
* The amount of cursor movement.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt b/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt
index 0a290b1..833ff11 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt
@@ -16,8 +16,6 @@
package androidx.ui.input
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY
import androidx.ui.text.TextRange
import java.lang.IllegalArgumentException
@@ -25,10 +23,7 @@
* The editing buffer
*
* This class manages the all editing relate states, editing buffers, selection, styles, etc.
- *
- * @hide
*/
-@RestrictTo(LIBRARY)
class EditingBuffer(
/**
* The initial text of this editing buffer
@@ -53,13 +48,13 @@
/**
* The inclusive selection start offset
*/
- var selectionStart = initialSelection.min
+ internal var selectionStart = initialSelection.min
private set
/**
* The exclusive selection end offset
*/
- var selectionEnd = initialSelection.max
+ internal var selectionEnd = initialSelection.max
private set
/**
@@ -67,7 +62,7 @@
*
* If there is no composing text, returns -1
*/
- var compositionStart = NOWHERE
+ internal var compositionStart = NOWHERE
private set
/**
@@ -75,18 +70,18 @@
*
* If there is no composing text, returns -1
*/
- var compositionEnd = NOWHERE
+ internal var compositionEnd = NOWHERE
private set
/**
* Helper function that returns true if the editing buffer has composition text
*/
- fun hasComposition(): Boolean = compositionStart != NOWHERE
+ internal fun hasComposition(): Boolean = compositionStart != NOWHERE
/**
* Helper accessor for cursor offset
*/
- var cursor: Int
+ internal var cursor: Int
/**
* Return the cursor offset.
*
@@ -104,12 +99,12 @@
/**
* [] operator for the character at the index.
*/
- operator fun get(index: Int): Char = gapBuffer[index]
+ internal operator fun get(index: Int): Char = gapBuffer[index]
/**
* Returns the length of the buffer.
*/
- val length: Int get() = gapBuffer.length
+ internal val length: Int get() = gapBuffer.length
init {
val start = initialSelection.min
@@ -137,7 +132,7 @@
* @throws IndexOutOfBoundsException if start or end offset is outside of current buffer
* @throws IllegalArgumentException if start is larger than end. (reversed range)
*/
- fun replace(start: Int, end: Int, text: String) {
+ internal fun replace(start: Int, end: Int, text: String) {
if (start < 0 || start > gapBuffer.length) {
throw IndexOutOfBoundsException(
@@ -176,7 +171,7 @@
* Different from replace method, this doesn't move cursor location to the end of modified text.
* Instead, preserve the selection with adjusting the deleted text.
*/
- fun delete(start: Int, end: Int) {
+ internal fun delete(start: Int, end: Int) {
val deleteRange = TextRange(start, end)
if (deleteRange.intersects(TextRange(selectionStart, selectionEnd))) {
// Currently only target for deleteSurroundingText/deleteSurroundingTextInCodePoints.
@@ -279,7 +274,7 @@
* @throws IndexOutOfBoundsException if start or end offset is outside of current buffer.
* @throws IllegalArgumentException if start is larger than end. (reversed range)
*/
- fun setSelection(start: Int, end: Int) {
+ internal fun setSelection(start: Int, end: Int) {
if (start < 0 || start > gapBuffer.length) {
throw IndexOutOfBoundsException(
"start ($start) offset is outside of text region ${gapBuffer.length}")
@@ -309,7 +304,7 @@
* @throws IllegalArgumentException if start is larger than or equal to end. (reversed or
* collapsed range)
*/
- fun setComposition(start: Int, end: Int) {
+ internal fun setComposition(start: Int, end: Int) {
if (start < 0 || start > gapBuffer.length) {
throw IndexOutOfBoundsException(
"start ($start) offset is outside of text region ${gapBuffer.length}")
@@ -329,7 +324,7 @@
/**
* Removes the ongoing composition text and reset the composition range.
*/
- fun cancelComposition() {
+ internal fun cancelComposition() {
replace(compositionStart, compositionEnd, "")
compositionStart = NOWHERE
compositionEnd = NOWHERE
@@ -338,7 +333,7 @@
/**
* Commits the ongoing composition text and reset the composition range.
*/
- fun commitComposition() {
+ internal fun commitComposition() {
compositionStart = NOWHERE
compositionEnd = NOWHERE
}
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt b/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt
index e18c421..73b815d 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt
@@ -18,6 +18,8 @@
import android.util.Log
import androidx.annotation.RestrictTo
+import kotlin.math.max
+import kotlin.math.min
/**
* The gap buffer implementation
@@ -235,26 +237,30 @@
* @param end an exclusive end offset for replacement
* @param text a text to replace
*/
- fun replace(start: Int, end: Int, buf: String) {
+ fun replace(start: Int, end: Int, text: String) {
val buffer = buffer
if (buffer == null) { // First time to create gap buffer
- val charArray = CharArray(Math.max(BUF_SIZE, buf.length + 2 * SURROUNDING_SIZE))
+ val charArray = CharArray(max(BUF_SIZE, text.length + 2 * SURROUNDING_SIZE))
// Convert surrounding text into buffer.
- val leftCopyCount = Math.min(start, SURROUNDING_SIZE)
- val rightCopyCount = Math.min(text.length - end, SURROUNDING_SIZE)
+ val leftCopyCount = min(start, SURROUNDING_SIZE)
+ val rightCopyCount = min(this.text.length - end, SURROUNDING_SIZE)
// Copy left surrounding
- text.toCharArray(charArray, 0, start - leftCopyCount, start)
+ this.text.toCharArray(charArray, 0, start - leftCopyCount, start)
// Copy right surrounding
- text.toCharArray(charArray, charArray.size - rightCopyCount, end, end + rightCopyCount)
+ this.text.toCharArray(charArray,
+ charArray.size - rightCopyCount,
+ end,
+ end + rightCopyCount
+ )
// Copy given text into buffer
- buf.toCharArray(charArray, leftCopyCount)
+ text.toCharArray(charArray, leftCopyCount)
this.buffer = GapBuffer(charArray,
- leftCopyCount + buf.length, // gap start
+ leftCopyCount + text.length, // gap start
charArray.size - rightCopyCount) // gap end
bufStart = start - leftCopyCount
bufEnd = end + rightCopyCount
@@ -267,14 +273,14 @@
if (bufferStart < 0 || bufferEnd > buffer.length()) {
// Text modification outside of gap buffer has requested. Flush the buffer and try it
// again.
- text = toString()
+ this.text = toString()
this.buffer = null
bufStart = NOWHERE
bufEnd = NOWHERE
- return replace(start, end, buf)
+ return replace(start, end, text)
}
- buffer.replace(bufferStart, bufferEnd, buf)
+ buffer.replace(bufferStart, bufferEnd, text)
}
/**
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt b/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt
index 67f2ee9..1f19c4e 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt
@@ -19,48 +19,48 @@
/**
* Enums used for indicating IME action.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_MASK_ACTION
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_MASK_ACTION>
*/
enum class ImeAction {
/**
* An IME action used to represent that any IME action is associated.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_UNSPECIFIED
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_UNSPECIFIED>
*/
Unspecified,
/**
* An IME action used to represent that no IME action is available in editor.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_NONE
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_NONE>
*/
NoAction,
/**
* An IME action used to represent that the "enter" key works as "go" action.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_GO
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_GO>
*/
Go,
/**
* An IME action used to represent that the "enter" key works as "search" action.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEARCH
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEARCH>
*/
Search,
/**
* An IME action used to represent that the "enter" key works as "send" action.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEND
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEND>
*/
Send,
/**
* An IME action used to represent that the "enter" key works as "previous" action.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_PREVIOUS
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_PREVIOUS>
*/
Previous,
@@ -74,7 +74,7 @@
/**
* An IME action used to represent that the "enter" key works as "done" action.
*
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_DONE
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_DONE>
*/
Done
}
\ No newline at end of file
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt b/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt
index 1c8d5db..b43beb1 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt
@@ -16,14 +16,9 @@
package androidx.ui.input
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY
/**
* An interface of listening IME events.
- *
- * @hide
*/
-@RestrictTo(LIBRARY)
interface InputEventListener {
/**
* Called when IME sends some input events.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt b/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt
index 1581d26..ab3327c 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt
@@ -16,9 +16,10 @@
package androidx.ui.input
-import androidx.annotation.RestrictTo
import androidx.ui.text.TextRange
import androidx.ui.text.substring
+import kotlin.math.max
+import kotlin.math.min
/**
* Stores an input state for IME
@@ -26,9 +27,7 @@
* IME can request editor state with calling getTextBeforeCursor, getSelectedText, etc.
* This class stores a snapshot of the input state of the edit buffer and provide utility functions
* for answering these information retrieval requests.
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY)
data class InputState(
/**
* A text visible to IME
@@ -53,13 +52,13 @@
* Helper function for getting text before selection range.
*/
fun getTextBeforeSelection(maxChars: Int): String =
- text.substring(Math.max(0, selection.min - maxChars), selection.min)
+ text.substring(max(0, selection.min - maxChars), selection.min)
/**
* Helper function for getting text after selection range.
*/
fun getTextAfterSelection(maxChars: Int): String =
- text.substring(selection.max, Math.min(selection.max + maxChars, text.length))
+ text.substring(selection.max, min(selection.max + maxChars, text.length))
/**
* Helper function for getting text currently selected.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt b/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt
index af4e201..968a0d6 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt
@@ -16,7 +16,6 @@
package androidx.ui.input
-import androidx.annotation.RestrictTo
import androidx.ui.engine.geometry.Rect
/**
@@ -30,26 +29,19 @@
/**
* A special session token which represents there is no active input session.
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY)
const val NO_SESSION: InputSessionToken = 0
/**
* A special session token which represents the session couldn't be established.
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY)
const val INVALID_SESSION: InputSessionToken = -1
/**
* Provide a communication with platform text input service.
- *
- * Open for testing purpose.
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-open class TextInputService(val platformTextInputService: PlatformTextInputService) {
+// Open for testing purposes.
+open class TextInputService(private val platformTextInputService: PlatformTextInputService) {
private var nextSessionToken: Int = 1
private var currentSessionToken: InputSessionToken = NO_SESSION
@@ -113,10 +105,8 @@
}
/**
- * An interface for text input service.
- * @hide
+ * Platform specific text input service.
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY)
interface PlatformTextInputService {
/**
* Start text input session for given client.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt b/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt
index d514202..4504c34 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt
@@ -16,7 +16,6 @@
package androidx.ui.input
-import androidx.annotation.RestrictTo
import androidx.ui.text.AnnotatedString
/**
@@ -47,6 +46,16 @@
* @see VisualTransformation
*/
fun transformedToOriginal(offset: Int): Int
+
+ companion object {
+ /**
+ * The offset map used for identity mapping.
+ */
+ val identityOffsetMap = object : OffsetMap {
+ override fun originalToTransformed(offset: Int): Int = offset
+ override fun transformedToOriginal(offset: Int): Int = offset
+ }
+ }
}
/**
@@ -108,18 +117,7 @@
override fun filter(text: AnnotatedString): TransformedText {
return TransformedText(
AnnotatedString(Character.toString(mask).repeat(text.text.length)),
- identityOffsetMap
+ OffsetMap.identityOffsetMap
)
}
}
-
-/**
- * The offset map used for identity mapping.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-val identityOffsetMap = object : OffsetMap {
- override fun originalToTransformed(offset: Int): Int = offset
- override fun transformedToOriginal(offset: Int): Int = offset
-}
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt b/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt
index 6516fb9..a415d9e 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt
@@ -16,6 +16,7 @@
package androidx.ui.text
+import androidx.compose.Immutable
import androidx.ui.text.platform.PlatformLocale
import androidx.ui.text.platform.platformLocaleDelegate
@@ -28,6 +29,7 @@
*
* @see [TextStyle]
*/
+@Immutable
class Locale internal constructor(internal val platformLocale: PlatformLocale) {
companion object {
/**
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt b/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt
index 5d0f6b8..70cceb8 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt
@@ -16,6 +16,7 @@
package androidx.ui.text
+import androidx.compose.Immutable
import androidx.ui.text.platform.platformLocaleDelegate
/**
@@ -23,6 +24,7 @@
*
* @see [TextStyle]
*/
+@Immutable
data class LocaleList constructor(val localeList: List<Locale>) : Collection<Locale> {
companion object {
/**
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt b/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt
index bc3d9b20..b6245a3 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt
@@ -16,6 +16,7 @@
package androidx.ui.text
+import androidx.compose.Immutable
import androidx.ui.core.Sp
import androidx.ui.text.style.TextAlign
import androidx.ui.text.style.TextDirectionAlgorithm
@@ -40,6 +41,7 @@
* @see [Paragraph]
* @see [AnnotatedString]
*/
+@Immutable
data class ParagraphStyle constructor(
val textAlign: TextAlign? = null,
val textDirectionAlgorithm: TextDirectionAlgorithm? = null,
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt b/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt
index f717759..7fc3a4d 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt
@@ -16,8 +16,6 @@
package androidx.ui.text
-import androidx.annotation.RestrictTo
-
/**
* A [TextSpan] object can be styled using its [style] property.
* The style will be applied to the [text] and the [children].
@@ -31,10 +29,7 @@
*
* @param children Additional spans to include as children. If both [text] and [children] are
* non-null, the text will precede the children. The list must not contain any nulls.
- *
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class TextSpan(
val style: TextStyle? = null,
val text: String? = null,
@@ -45,7 +40,7 @@
* Walks this text span and its descendants in pre-order and calls [visitor]
* for each span that has text.
*/
- fun visitTextSpan(visitor: (span: TextSpan) -> Boolean): Boolean {
+ internal fun visitTextSpan(visitor: (span: TextSpan) -> Boolean): Boolean {
if (text != null) {
if (!visitor(this)) {
return false
@@ -87,9 +82,7 @@
/**
* Convert a [TextSpan] into an [AnnotatedString].
- * @hide
*/
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun TextSpan.toAnnotatedString(): AnnotatedString {
return with(AnnotatedString.Builder()) {
annotatedStringVisitor(this)
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt b/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt
index ace6fbf..9636396 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt
@@ -16,10 +16,12 @@
package androidx.ui.text
+import androidx.compose.Immutable
import androidx.ui.core.Em
import androidx.ui.core.Sp
import androidx.ui.core.em
import androidx.ui.core.isInherit
+import androidx.ui.core.lerp
import androidx.ui.core.sp
import androidx.ui.graphics.Color
import androidx.ui.graphics.Shadow
@@ -64,6 +66,7 @@
*
* @see [AnnotatedString]
*/
+@Immutable
data class TextStyle(
val color: Color? = null,
val fontSize: Sp = Sp.Inherit,
@@ -113,22 +116,6 @@
}
}
-private fun lerpColor(a: Color?, b: Color?, t: Float): Color? {
- if (a == null && b == null) {
- return null
- }
- val start = a ?: b!!.copy(alpha = 0f)
- val end = b ?: a!!.copy(alpha = 0f)
- return lerp(start, end, t)
-}
-
-private fun lerpFloat(a: Float?, b: Float?, t: Float, default: Float = 0f): Float? {
- if (a == null && b == null) return null
- val start = a ?: default
- val end = b ?: default
- return lerp(start, end, t)
-}
-
/**
* @param a An sp value. Maybe [Sp.Inherit]
* @param b An sp value. Maybe [Sp.Inherit]
@@ -140,14 +127,7 @@
return androidx.ui.core.lerp(start, end, t)
}
-private fun lerpEm(a: Em?, b: Em?, t: Float, default: Em = 0f.em): Em? {
- if (a == null && b == null) return null
- val start = a ?: default
- val end = b ?: default
- return androidx.ui.core.lerp(start, end, t)
-}
-
-private fun <T> lerpDiscrete(a: T?, b: T?, t: Float): T? = if (t < 0.5) a else b
+private fun <T> lerpDiscrete(a: T, b: T, t: Float): T = if (t < 0.5) a else b
/**
* Interpolate between two text styles.
@@ -162,56 +142,25 @@
* between [start] and [stop]. The interpolation can be extrapolated beyond 0.0 and
* 1.0, so negative values and values greater than 1.0 are valid.
*/
-fun lerp(start: TextStyle? = null, stop: TextStyle? = null, fraction: Float): TextStyle? {
- val aIsNull = start == null
- val bIsNull = stop == null
-
- if (aIsNull && bIsNull) return null
-
- if (start == null) {
- val newB = stop?.copy() ?: TextStyle()
- return if (fraction < 0.5) {
- TextStyle(
- color = lerpColor(null, newB.color, fraction),
- fontWeight = lerp(null, newB.fontWeight, fraction)
- )
- } else {
- newB.copy(
- color = lerpColor(null, newB.color, fraction),
- fontWeight = lerp(null, newB.fontWeight, fraction)
- )
- }
- }
-
- if (stop == null) {
- return if (fraction < 0.5) {
- start.copy(
- color = lerpColor(start.color, null, fraction),
- fontWeight = lerp(start.fontWeight, null, fraction)
- )
- } else {
- TextStyle(
- color = lerpColor(start.color, null, fraction),
- fontWeight = lerp(start.fontWeight, null, fraction)
- )
- }
- }
-
+fun lerp(start: TextStyle, stop: TextStyle, fraction: Float): TextStyle {
return TextStyle(
- color = lerpColor(start.color, stop.color, fraction),
+ color = lerp(start.color ?: Color.Black, stop.color ?: Color.Black, fraction),
fontFamily = lerpDiscrete(
start.fontFamily,
stop.fontFamily,
fraction
),
fontSize = lerpSp(start.fontSize, stop.fontSize, fraction),
- fontSizeScale = lerpFloat(
- start.fontSizeScale,
- stop.fontSizeScale,
- fraction,
- 1f
+ fontSizeScale = lerp(
+ start.fontSizeScale ?: 1.0f,
+ stop.fontSizeScale ?: 1.0f,
+ fraction
),
- fontWeight = lerp(start.fontWeight, stop.fontWeight, fraction),
+ fontWeight = lerp(
+ start.fontWeight ?: FontWeight.Normal,
+ stop.fontWeight ?: FontWeight.Normal,
+ fraction
+ ),
fontStyle = lerpDiscrete(
start.fontStyle,
stop.fontStyle,
@@ -227,9 +176,9 @@
stop.fontFeatureSettings,
fraction
),
- letterSpacing = lerpEm(
- start.letterSpacing,
- stop.letterSpacing,
+ letterSpacing = lerp(
+ start.letterSpacing ?: 0.em,
+ stop.letterSpacing ?: 0.em,
fraction
),
baselineShift = lerp(
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt b/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt
index f40df88..c98da42 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt
@@ -16,6 +16,8 @@
package androidx.ui.text.font
+import androidx.compose.Immutable
+
/**
* Defines a font family. It can be constructed via a generic font family such as serif, sans-serif
* (i.e. FontFamily("sans-serif"). It can also be constructed by a set of custom fonts.
@@ -23,6 +25,7 @@
* @sample androidx.ui.text.samples.FontFamilySansSerifSample
* @sample androidx.ui.text.samples.CustomFontFamilySample
*/
+@Immutable
data class FontFamily private constructor(val genericFamily: String?, val fonts: List<Font>) :
List<Font> by fonts {
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt b/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt
index c2e9a2d..2bc452c 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt
@@ -15,6 +15,7 @@
*/
package androidx.ui.text.font
+import androidx.compose.Immutable
import androidx.ui.lerp
/**
@@ -23,6 +24,7 @@
* @see [Font]
* @see [FontFamily]
*/
+@Immutable
/* inline */ data class FontWeight private constructor(
/**
* Can be in the range of [1,1000]
@@ -108,12 +110,8 @@
* Values for [fraction] are usually obtained from an [Animation<Float>], such as
* an `AnimationController`.
*/
-fun lerp(start: FontWeight?, stop: FontWeight?, fraction: Float): FontWeight {
- val index = lerp(
- start?.index ?: FontWeight.Normal.index,
- stop?.index ?: FontWeight.Normal.index,
- fraction
- ).coerceIn(0, FontWeight.values.size - 1)
+fun lerp(start: FontWeight, stop: FontWeight, fraction: Float): FontWeight {
+ val index = lerp(start.index, stop.index, fraction).coerceIn(0, FontWeight.values.size - 1)
return FontWeight.values[index]
}
\ No newline at end of file
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt
index edd2aa5..8f4c742 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt
@@ -16,6 +16,7 @@
package androidx.ui.text.style
+import androidx.compose.Immutable
import androidx.ui.lerp
/**
@@ -26,6 +27,7 @@
*
* @param multiplier shift the baseline by multiplier * (baseline - ascent)
*/
+@Immutable
/*inline*/ data class BaselineShift constructor(
val multiplier: Float
) {
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt
index be5f466..fa73392 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt
@@ -15,9 +15,12 @@
*/
package androidx.ui.text.style
+import androidx.compose.Immutable
+
/**
* Defines a horizontal line to be drawn on the text.
*/
+@Immutable
data class TextDecoration internal constructor(val mask: Int) {
companion object {
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt
index c4cd690..0283448 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt
@@ -16,6 +16,7 @@
package androidx.ui.text.style
+import androidx.compose.Immutable
import androidx.ui.lerp
/**
@@ -25,6 +26,7 @@
* @param skewX The shear of the text on the horizontal direction. A pixel at (x, y), where y is
* the distance above baseline, will be transformed to (x + y * skewX, y).
*/
+@Immutable
data class TextGeometricTransform(
val scaleX: Float? = null,
val skewX: Float? = null
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt
index 7e301e8..ff42d41 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt
@@ -16,6 +16,7 @@
package androidx.ui.text.style
+import androidx.compose.Immutable
import androidx.ui.core.Sp
import androidx.ui.core.lerp
import androidx.ui.core.sp
@@ -26,6 +27,7 @@
* @param firstLine the amount of indentation applied to the first line.
* @param restLine the amount of indentation applied to every line except the first line.
*/
+@Immutable
data class TextIndent(
val firstLine: Sp = 0.sp,
val restLine: Sp = 0.sp
diff --git a/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt b/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt
index 28ccbeb..d5ab64e 100644
--- a/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt
+++ b/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt
@@ -431,81 +431,6 @@
}
@Test
- fun `lerp with both Null Textstyles`() {
- val newTextStyle = lerp(fraction = 1.0f)
-
- assertThat(newTextStyle).isEqualTo(null)
- }
-
- @Test
- fun `lerp color with a is Null and t is smaller than half`() {
- val color = Color(0xFF00FF00)
- val t = 0.3f
- val textStyle = TextStyle(color = color)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.color).isEqualTo(
- lerp(
- start = color.copy(alpha = 0f),
- stop = color,
- fraction = t
- )
- )
- }
-
- @Test
- fun `lerp color with a is Null and t is larger than half`() {
- val color = Color(0xFF00FF00)
- val t = 0.8f
- val textStyle = TextStyle(color = color)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.color).isEqualTo(
- lerp(
- start = color.copy(alpha = 0f),
- stop = color,
- fraction = t
- )
- )
- }
-
- @Test
- fun `lerp color with b is Null and t is smaller than half`() {
- val color = Color(0xFF00FF00)
- val t = 0.3f
- val textStyle = TextStyle(color = color)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.color).isEqualTo(
- lerp(
- start = color,
- stop = color.copy(alpha = 0f),
- fraction = t
- )
- )
- }
-
- @Test
- fun `lerp color with b is Null and t is larger than half`() {
- val color = Color(0xFF00FF00)
- val t = 0.8f
- val textStyle = TextStyle(color = color)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.color).isEqualTo(
- lerp(
- start = color,
- stop = color.copy(alpha = 0f),
- fraction = t
- )
- )
- }
-
- @Test
fun `lerp color with a and b are not Null`() {
val color1 = Color(0xFF00FF00)
val color2 = Color(0x00FFFF00)
@@ -515,51 +440,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.color).isEqualTo(lerp(start = color1, stop = color2, fraction = t))
- }
-
- @Test
- fun `lerp fontFamily with a is Null and t is smaller than half`() {
- val fontFamily = FontFamily(genericFamily = "sans-serif")
- val t = 0.3f
- val textStyle = TextStyle(fontFamily = fontFamily)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFamily).isNull()
- }
-
- @Test
- fun `lerp fontFamily with a is Null and t is larger than half`() {
- val fontFamily = FontFamily(genericFamily = "sans-serif")
- val t = 0.7f
- val textStyle = TextStyle(fontFamily = fontFamily)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily)
- }
-
- @Test
- fun `lerp fontFamily with b is Null and t is smaller than half`() {
- val fontFamily = FontFamily(genericFamily = "sans-serif")
- val t = 0.3f
- val textStyle = TextStyle(fontFamily = fontFamily)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily)
- }
-
- @Test
- fun `lerp fontFamily with b is Null and t is larger than half`() {
- val fontFamily = FontFamily(genericFamily = "sans-serif")
- val t = 0.7f
- val textStyle = TextStyle(fontFamily = fontFamily)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFamily).isNull()
+ assertThat(newTextStyle.color).isEqualTo(lerp(start = color1, stop = color2, fraction = t))
}
@Test
@@ -572,7 +453,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily1)
+ assertThat(newTextStyle.fontFamily).isEqualTo(fontFamily1)
}
@Test
@@ -585,53 +466,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily2)
- }
-
- @Test
- fun `lerp fontSize with a is Null and t is smaller than half`() {
- val fontSize = 8.sp
- val t = 0.3f
- val textStyle = TextStyle(fontSize = fontSize)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle).isNotNull()
- assertThat(newTextStyle!!.fontSize.isInherit()).isTrue()
- }
-
- @Test
- fun `lerp fontSize with a is Null and t is larger than half`() {
- val fontSize = 8.sp
- val t = 0.8f
- val textStyle = TextStyle(fontSize = fontSize)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontSize).isEqualTo(fontSize)
- }
-
- @Test
- fun `lerp fontSize with b is Null and t is smaller than half`() {
- val fontSize = 8.sp
- val t = 0.3f
- val textStyle = TextStyle(fontSize = fontSize)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontSize).isEqualTo(fontSize)
- }
-
- @Test
- fun `lerp fontSize with b is Null and t is larger than half`() {
- val fontSize = 8.sp
- val t = 0.8f
- val textStyle = TextStyle(fontSize = fontSize)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle).isNotNull()
- assertThat(newTextStyle!!.fontSize.isInherit()).isTrue()
+ assertThat(newTextStyle.fontFamily).isEqualTo(fontFamily2)
}
@Test
@@ -645,7 +480,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
// a + (b - a) * t = 8.0f + (16.0f - 8.0f) * 0.8f = 14.4f
- assertThat(newTextStyle?.fontSize).isEqualTo(14.4.sp)
+ assertThat(newTextStyle.fontSize).isEqualTo(14.4.sp)
}
@Test
@@ -659,90 +494,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
// a + (b - a) * t = 2.0f + (4.0f - 2.0f) * 0.8f = 3.6f
- assertThat(newTextStyle?.fontSizeScale).isEqualTo(3.6f)
- }
-
- @Test
- fun `lerp fontSizeScale with a not Null and b is Null`() {
- val fontSizeScale = 2.0f
- val t = 0.8f
- val textStyle1 = TextStyle(fontSizeScale = fontSizeScale)
- val textStyle2 = TextStyle()
-
- val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
-
- // b is Null and is considered 1.0f
- // a + (b - a) * t = 2.0f + (1.0f - 2.0f) * 0.8f = 1.2f
- assertThat(newTextStyle?.fontSizeScale).isEqualTo(1.2f)
- }
-
- @Test
- fun `lerp fontSizeScale with a is Null and b not Null`() {
- val fontSizeScale = 2.0f
- val t = 0.8f
- val textStyle1 = TextStyle()
- val textStyle2 = TextStyle(fontSizeScale = fontSizeScale)
-
- val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
-
- // a is Null and is considered 1.0f
- // a + (b - a) * t = 1.0f + (2.0f - 1.0f) * 0.8f = 1.8f
- assertThat(newTextStyle?.fontSizeScale).isEqualTo(1.8f)
- }
-
- @Test
- fun `lerp fontSizeScale with a and b are Null`() {
- val t = 0.8f
- val textStyle1 = TextStyle()
- val textStyle2 = TextStyle()
-
- val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
-
- assertThat(newTextStyle?.fontSizeScale).isNull()
- }
-
- @Test
- fun `lerp fontWeight with a is Null and t is smaller than half`() {
- val fontWeight = FontWeight.W700
- val t = 0.3f
- val textStyle = TextStyle(fontWeight = fontWeight)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(null, fontWeight, t))
- }
-
- @Test
- fun `lerp fontWeight with a is Null and t is larger than half`() {
- val fontWeight = FontWeight.W700
- val t = 0.8f
- val textStyle = TextStyle(fontWeight = fontWeight)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(null, fontWeight, t))
- }
-
- @Test
- fun `lerp fontWeight with b is Null and t is smaller than half`() {
- val fontWeight = FontWeight.W700
- val t = 0.3f
- val textStyle = TextStyle(fontWeight = fontWeight)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(fontWeight, null, t))
- }
-
- @Test
- fun `lerp fontWeight with b is Null and t is larger than half`() {
- val fontWeight = FontWeight.W700
- val t = 0.8f
- val textStyle = TextStyle(fontWeight = fontWeight)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(fontWeight, null, t))
+ assertThat(newTextStyle.fontSizeScale).isEqualTo(3.6f)
}
@Test
@@ -755,51 +507,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(fontWeight1, fontWeight2, t))
- }
-
- @Test
- fun `lerp fontStyle with a is Null and t is smaller than half`() {
- val fontStyle = FontStyle.Italic
- val t = 0.3f
- val textStyle = TextStyle(fontStyle = fontStyle)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontStyle).isNull()
- }
-
- @Test
- fun `lerp fontStyle with a is Null and t is larger than half`() {
- val fontStyle = FontStyle.Italic
- val t = 0.8f
- val textStyle = TextStyle(fontStyle = fontStyle)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle)
- }
-
- @Test
- fun `lerp fontStyle with b is Null and t is smaller than half`() {
- val fontStyle = FontStyle.Italic
- val t = 0.3f
- val textStyle = TextStyle(fontStyle = fontStyle)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle)
- }
-
- @Test
- fun `lerp fontStyle with b is Null and t is larger than half`() {
- val fontStyle = FontStyle.Italic
- val t = 0.8f
- val textStyle = TextStyle(fontStyle = fontStyle)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontStyle).isNull()
+ assertThat(newTextStyle.fontWeight).isEqualTo(lerp(fontWeight1, fontWeight2, t))
}
@Test
@@ -813,7 +521,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle1)
+ assertThat(newTextStyle.fontStyle).isEqualTo(fontStyle1)
}
@Test
@@ -827,51 +535,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle2)
- }
-
- @Test
- fun `lerp fontSynthesis with a is Null and t is smaller than half`() {
- val fontSynthesis = FontSynthesis.Style
- val t = 0.3f
- val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontSynthesis).isNull()
- }
-
- @Test
- fun `lerp fontSynthesis with a is Null and t is larger than half`() {
- val fontSynthesis = FontSynthesis.Style
- val t = 0.8f
- val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis)
- }
-
- @Test
- fun `lerp fontSynthesis with b is Null and t is smaller than half`() {
- val fontSynthesis = FontSynthesis.Style
- val t = 0.3f
- val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis)
- }
-
- @Test
- fun `lerp fontSynthesis with b is Null and t is larger than half`() {
- val fontSynthesis = FontSynthesis.Style
- val t = 0.8f
- val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontSynthesis).isNull()
+ assertThat(newTextStyle.fontStyle).isEqualTo(fontStyle2)
}
@Test
@@ -886,7 +550,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis1)
+ assertThat(newTextStyle.fontSynthesis).isEqualTo(fontSynthesis1)
}
@Test
@@ -901,51 +565,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis2)
- }
-
- @Test
- fun `lerp fontFeatureSettings with a is Null and t is smaller than half`() {
- val fontFeatureSettings = "\"kern\" 0"
- val t = 0.3f
- val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFeatureSettings).isNull()
- }
-
- @Test
- fun `lerp fontFeatureSettings with a is Null and t is larger than half`() {
- val fontFeatureSettings = "\"kern\" 0"
- val t = 0.8f
- val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings)
- }
-
- @Test
- fun `lerp fontFeatureSettings with b is Null and t is smaller than half`() {
- val fontFeatureSettings = "\"kern\" 0"
- val t = 0.3f
- val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings)
- }
-
- @Test
- fun `lerp fontFeatureSettings with b is Null and t is larger than half`() {
- val fontFeatureSettings = "\"kern\" 0"
- val t = 0.8f
- val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.fontFeatureSettings).isNull()
+ assertThat(newTextStyle.fontSynthesis).isEqualTo(fontSynthesis2)
}
@Test
@@ -960,7 +580,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings1)
+ assertThat(newTextStyle.fontFeatureSettings).isEqualTo(fontFeatureSettings1)
}
@Test
@@ -975,51 +595,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings2)
- }
-
- @Test
- fun `lerp letterSpacing with a is Null and t is smaller than half`() {
- val letterSpacing = 2.em
- val t = 0.3f
- val textStyle = TextStyle(letterSpacing = letterSpacing)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.letterSpacing).isNull()
- }
-
- @Test
- fun `lerp letterSpacing with a is Null and t is larger than half`() {
- val letterSpacing = 2.em
- val t = 0.8f
- val textStyle = TextStyle(letterSpacing = letterSpacing)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.letterSpacing).isEqualTo(letterSpacing)
- }
-
- @Test
- fun `lerp letterSpacing with b is Null and t is smaller than half`() {
- val letterSpacing = 2.em
- val t = 0.3f
- val textStyle = TextStyle(letterSpacing = letterSpacing)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.letterSpacing).isEqualTo(letterSpacing)
- }
-
- @Test
- fun `lerp letterSpacing with b is Null and t is larger than half`() {
- val letterSpacing = 2.em
- val t = 0.8f
- val textStyle = TextStyle(letterSpacing = letterSpacing)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.letterSpacing).isNull()
+ assertThat(newTextStyle.fontFeatureSettings).isEqualTo(fontFeatureSettings2)
}
@Test
@@ -1032,55 +608,11 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.baselineShift)
+ assertThat(newTextStyle.baselineShift)
.isEqualTo(lerp(baselineShift1, baselineShift2, t))
}
@Test
- fun `lerp textGeometricTransform with a is Null and t is smaller than half`() {
- val textTransform = TextGeometricTransform(scaleX = 1.5f)
- val t = 0.3f
- val textStyle = TextStyle(textGeometricTransform = textTransform)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.textGeometricTransform).isNull()
- }
-
- @Test
- fun `lerp textGeometricTransform with a is Null and t is larger than half`() {
- val textTransform = TextGeometricTransform(scaleX = 1.5f)
- val t = 0.7f
- val textStyle = TextStyle(textGeometricTransform = textTransform)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.textGeometricTransform).isEqualTo(textTransform)
- }
-
- @Test
- fun `lerp textGeometricTransform with b is Null and t is smaller than half`() {
- val textTransform = TextGeometricTransform(scaleX = 1.5f)
- val t = 0.3f
- val textStyle = TextStyle(textGeometricTransform = textTransform)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.textGeometricTransform).isEqualTo(textTransform)
- }
-
- @Test
- fun `lerp textGeometricTransform with b is Null and t is larger than half`() {
- val textTransform = TextGeometricTransform(scaleX = 1.5f)
- val t = 0.7f
- val textStyle = TextStyle(textGeometricTransform = textTransform)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.textGeometricTransform).isNull()
- }
-
- @Test
fun `lerp textGeometricTransform with a and b are not Null`() {
val textTransform1 =
TextGeometricTransform(scaleX = 1.5f, skewX = 0.1f)
@@ -1092,55 +624,11 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.textGeometricTransform)
+ assertThat(newTextStyle.textGeometricTransform)
.isEqualTo(lerp(textTransform1, textTransform2, t))
}
@Test
- fun `lerp locale with a is Null and t is smaller than half`() {
- val localeList = LocaleList("en-US")
- val t = 0.2f
- val textStyle = TextStyle(localeList = localeList)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.localeList).isNull()
- }
-
- @Test
- fun `lerp locale with a is Null and t is larger than half`() {
- val localeList = LocaleList("en-US")
- val t = 0.8f
- val textStyle = TextStyle(localeList = localeList)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.localeList).isEqualTo(localeList)
- }
-
- @Test
- fun `lerp locale with b is Null and t is smaller than half`() {
- val localeList = LocaleList("en-US")
- val t = 0.2f
- val textStyle = TextStyle(localeList = localeList)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.localeList).isEqualTo(localeList)
- }
-
- @Test
- fun `lerp locale with b is Null and t is larger than half`() {
- val localeList = LocaleList("en-US")
- val t = 0.8f
- val textStyle = TextStyle(localeList = localeList)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.localeList).isNull()
- }
-
- @Test
fun `lerp locale with a and b are not Null and t is smaller than half`() {
val localeList1 = LocaleList("en-US")
val localeList2 = LocaleList("ja-JP")
@@ -1150,7 +638,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.localeList).isEqualTo(localeList1)
+ assertThat(newTextStyle.localeList).isEqualTo(localeList1)
}
@Test
@@ -1163,50 +651,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.localeList).isEqualTo(localeList2)
- }
-
- @Test
- fun `lerp background with a is Null and t is smaller than half`() {
- val color = Color(0xFF00FF00)
- val t = 0.2f
- val textStyle = TextStyle(background = color)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.background).isNull()
- }
-
- @Test
- fun `lerp background with a is Null and t is larger than half`() {
- val color = Color(0xFF00FF00)
- val t = 0.8f
- val textStyle = TextStyle(background = color)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.background).isEqualTo(color)
- }
-
- @Test
- fun `lerp background with b is Null and t is smaller than half`() {
- val color = Color(0xFF00FF00)
- val t = 0.2f
- val textStyle = TextStyle(background = color)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.background).isEqualTo(color)
- }
-
- @Test
- fun `lerp background with b is Null and t is larger than half`() {
- val t = 0.8f
- val textStyle = TextStyle(background = Color(0xFF00FF00))
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.background).isNull()
+ assertThat(newTextStyle.localeList).isEqualTo(localeList2)
}
@Test
@@ -1219,7 +664,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.background).isEqualTo(color1)
+ assertThat(newTextStyle.background).isEqualTo(color1)
}
@Test
@@ -1232,51 +677,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.background).isEqualTo(color2)
- }
-
- @Test
- fun `lerp decoration with a is Null and t is smaller than half`() {
- val decoration = TextDecoration.LineThrough
- val t = 0.2f
- val textStyle = TextStyle(decoration = decoration)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.decoration).isNull()
- }
-
- @Test
- fun `lerp decoration with a is Null and t is larger than half`() {
- val decoration = TextDecoration.LineThrough
- val t = 0.8f
- val textStyle = TextStyle(decoration = decoration)
-
- val newTextStyle = lerp(stop = textStyle, fraction = t)
-
- assertThat(newTextStyle?.decoration).isEqualTo(decoration)
- }
-
- @Test
- fun `lerp decoration with b is Null and t is smaller than half`() {
- val decoration = TextDecoration.LineThrough
- val t = 0.2f
- val textStyle = TextStyle(decoration = decoration)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.decoration).isEqualTo(decoration)
- }
-
- @Test
- fun `lerp decoration with b is Null and t is larger than half`() {
- val decoration = TextDecoration.LineThrough
- val t = 0.8f
- val textStyle = TextStyle(decoration = decoration)
-
- val newTextStyle = lerp(start = textStyle, fraction = t)
-
- assertThat(newTextStyle?.decoration).isNull()
+ assertThat(newTextStyle.background).isEqualTo(color2)
}
@Test
@@ -1289,7 +690,7 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.decoration).isEqualTo(decoration1)
+ assertThat(newTextStyle.decoration).isEqualTo(decoration1)
}
@Test
@@ -1302,6 +703,6 @@
val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
- assertThat(newTextStyle?.decoration).isEqualTo(decoration2)
+ assertThat(newTextStyle.decoration).isEqualTo(decoration2)
}
}
diff --git a/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt b/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt
index dc6d21b..b0d0b6d 100644
--- a/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt
+++ b/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt
@@ -22,32 +22,6 @@
@RunWith(JUnit4::class)
class FontWeightTest {
-
- @Test
- fun `lerp with null parameters`() {
- assertThat(lerp(null, null, 0.0f)).isEqualTo(
- FontWeight.Normal
- )
- }
-
- @Test
- fun `lerp with one null parameter should use normal for null value`() {
- assertThat(
- lerp(
- FontWeight.W200,
- null,
- 0.5f
- )
- ).isEqualTo(FontWeight.W300)
- assertThat(
- lerp(
- null,
- FontWeight.W200,
- 0.5f
- )
- ).isEqualTo(FontWeight.W300)
- }
-
@Test
fun `lerp at start returns start value`() {
assertThat(
diff --git a/work/workmanager-lint/src/main/java/androidx/work/lint/RemoveWorkManagerInitializerDetector.kt b/work/workmanager-lint/src/main/java/androidx/work/lint/RemoveWorkManagerInitializerDetector.kt
new file mode 100644
index 0000000..a300883
--- /dev/null
+++ b/work/workmanager-lint/src/main/java/androidx/work/lint/RemoveWorkManagerInitializerDetector.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2019 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.work.lint
+
+import com.android.SdkConstants.ANDROID_URI
+import com.android.SdkConstants.ATTR_NAME
+import com.android.SdkConstants.TOOLS_URI
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Context
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Location
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.XmlContext
+import com.android.tools.lint.detector.api.XmlScanner
+import org.jetbrains.uast.UClass
+import org.w3c.dom.Element
+import org.w3c.dom.Node
+import org.w3c.dom.NodeList
+import java.util.EnumSet
+
+class RemoveWorkManagerInitializerDetector : Detector(), SourceCodeScanner, XmlScanner {
+ private var removedDefaultInitializer = false
+ private var location: Location? = null
+ private var applicationImplementsConfigurationProvider = false
+
+ companion object {
+
+ private const val DESCRIPTION = "Remove androidx.work.impl.WorkManagerInitializer from " +
+ "your AndroidManifest.xml when using on-demand initialization."
+
+ val ISSUE = Issue.create(
+ id = "RemoveWorkManagerInitializer",
+ briefDescription = DESCRIPTION,
+ explanation = """
+ If an `android.app.Application` implements `androidx.work.Configuration.Provider`,
+ the default `androidx.work.impl.WorkManagerInitializer` needs to be removed from the
+ AndroidManifest.xml file.
+ """,
+ androidSpecific = true,
+ category = Category.CORRECTNESS,
+ severity = Severity.FATAL,
+ implementation = Implementation(
+ RemoveWorkManagerInitializerDetector::class.java,
+ EnumSet.of(Scope.JAVA_FILE, Scope.MANIFEST)
+ )
+ )
+
+ private const val ATTR_NODE = "node"
+
+ fun NodeList?.find(fn: (node: Node) -> Boolean): Node? {
+ if (this == null) {
+ return null
+ } else {
+ for (i in 0 until this.length) {
+ val node = this.item(i)
+ if (fn(node)) {
+ return node
+ }
+ }
+ return null
+ }
+ }
+ }
+
+ override fun getApplicableElements() = listOf("application")
+
+ override fun applicableSuperClasses() = listOf("androidx.work.Configuration.Provider")
+
+ override fun visitElement(context: XmlContext, element: Element) {
+ val providers = element.getElementsByTagName("provider")
+ val provider = providers.find { node ->
+ val name = node.attributes.getNamedItemNS(ANDROID_URI, ATTR_NAME)?.textContent
+ name == "androidx.work.impl.WorkManagerInitializer"
+ }
+ if (provider != null) {
+ location = context.getLocation(provider)
+ val remove = provider.attributes.getNamedItemNS(TOOLS_URI, ATTR_NODE)
+ if (remove?.textContent == "remove") {
+ removedDefaultInitializer = true
+ }
+ }
+ }
+
+ override fun visitClass(context: JavaContext, declaration: UClass) {
+ if (context.evaluator.inheritsFrom(
+ declaration.javaPsi,
+ "android.app.Application",
+ false
+ )
+ ) {
+ applicationImplementsConfigurationProvider = true
+ }
+ }
+
+ override fun afterCheckRootProject(context: Context) {
+ val location = location ?: Location.create(context.file)
+ if (applicationImplementsConfigurationProvider) {
+ if (!removedDefaultInitializer) {
+ context.report(
+ issue = ISSUE,
+ location = location,
+ message = DESCRIPTION
+ )
+ }
+ }
+ }
+}
diff --git a/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt b/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt
index 8e69bab..fb3e9e5 100644
--- a/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt
+++ b/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt
@@ -26,6 +26,7 @@
override val minApi: Int = CURRENT_API
override val issues: List<Issue> = listOf(
BadConfigurationProviderIssueDetector.ISSUE,
- PeriodicEnqueueIssueDetector.ISSUE
+ PeriodicEnqueueIssueDetector.ISSUE,
+ RemoveWorkManagerInitializerDetector.ISSUE
)
}
diff --git a/work/workmanager-lint/src/test/java/androidx/work/lint/RemoveWorkManagerInitializerDetectorTest.kt b/work/workmanager-lint/src/test/java/androidx/work/lint/RemoveWorkManagerInitializerDetectorTest.kt
new file mode 100644
index 0000000..99f532a
--- /dev/null
+++ b/work/workmanager-lint/src/test/java/androidx/work/lint/RemoveWorkManagerInitializerDetectorTest.kt
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2019 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.work.lint
+
+import androidx.work.lint.Stubs.ANDROID_APPLICATION
+import androidx.work.lint.Stubs.WORK_MANAGER_CONFIGURATION_PROVIDER
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest.kotlin
+import com.android.tools.lint.checks.infrastructure.TestFiles.manifest
+import com.android.tools.lint.checks.infrastructure.TestLintTask.lint
+import org.junit.Test
+
+class RemoveWorkManagerInitializerDetectorTest {
+ @Test
+ fun testNoWarningsWhenDefaultInitializerIsRemoved() {
+ val customApplication = kotlin(
+ "com/example/App.kt",
+ """
+ package com.example
+
+ import android.app.Application
+ import androidx.work.Configuration
+
+ class App: Application(), Configuration.Provider {
+ override fun onCreate() {
+
+ }
+
+ override fun getWorkManagerConfiguration(): Configuration = TODO()
+ }
+ """
+ ).indented().within("src")
+
+ val manifestWithNoInitializer = manifest(
+ """
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example">
+ <application>
+ <provider
+ android:name="androidx.work.impl.WorkManagerInitializer"
+ android:authorities="com.example.workmanager-init"
+ tools:node="remove"/>
+
+ </application>
+ </manifest>
+ """
+ ).indented()
+
+ lint().files(
+ // Manifest file
+ manifestWithNoInitializer,
+ // Source files
+ ANDROID_APPLICATION,
+ WORK_MANAGER_CONFIGURATION_PROVIDER,
+ customApplication
+ )
+ .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun testNoWarningsWhenNotUsingOnDemandInitialization() {
+ val customApplication = kotlin(
+ "com/example/App.kt",
+ """
+ package com.example
+
+ import android.app.Application
+ import androidx.work.Configuration
+
+ class App: Application() {
+ override fun onCreate() {
+
+ }
+ }
+ """
+ ).indented().within("src")
+
+ val manifestWithInitializer = manifest(
+ """
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example">
+ <application>
+ <provider
+ android:name="androidx.work.impl.WorkManagerInitializer"
+ android:authorities="com.example.workmanager-init"/>
+
+ </application>
+ </manifest>
+ """
+ ).indented()
+
+ lint().files(
+ // Manifest file
+ manifestWithInitializer,
+ // Source files
+ ANDROID_APPLICATION,
+ WORK_MANAGER_CONFIGURATION_PROVIDER,
+ customApplication
+ )
+ .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+ .run()
+ .expectClean()
+ }
+
+ @Test
+ fun failWhenUsingDefaultManifestMergeStrategy() {
+ val customApplication = kotlin(
+ "com/example/App.kt",
+ """
+ package com.example
+
+ import android.app.Application
+ import androidx.work.Configuration
+
+ class App: Application(), Configuration.Provider {
+ override fun onCreate() {
+
+ }
+
+ override fun getWorkManagerConfiguration(): Configuration = TODO()
+ }
+ """
+ ).indented().within("src")
+
+ val emptyManifest = manifest(
+ """
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example">
+ <application />
+ </manifest>
+ """
+ ).indented()
+
+ /* ktlint-disable max-line-length */
+ lint().files(
+ // Manifest file
+ emptyManifest,
+ // Source files
+ ANDROID_APPLICATION,
+ WORK_MANAGER_CONFIGURATION_PROVIDER,
+ customApplication
+ )
+ .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+ .run()
+ .expect("""
+ project0: Error: Remove androidx.work.impl.WorkManagerInitializer from your AndroidManifest.xml when using on-demand initialization. [RemoveWorkManagerInitializer]
+ 1 errors, 0 warnings
+ """.trimIndent())
+ /* ktlint-enable max-line-length */
+ }
+
+ @Test
+ fun failWhenManifestHasDefaultInitializer() {
+ val customApplication = kotlin(
+ "com/example/App.kt",
+ """
+ package com.example
+
+ import android.app.Application
+ import androidx.work.Configuration
+
+ class App: Application(), Configuration.Provider {
+ override fun onCreate() {
+
+ }
+
+ override fun getWorkManagerConfiguration(): Configuration = TODO()
+ }
+ """
+ ).indented().within("src")
+
+ val manifestWithInitializer = manifest(
+ """
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.example">
+ <application>
+ <provider
+ android:name="androidx.work.impl.WorkManagerInitializer"
+ android:authorities="com.example.workmanager-init"/>
+
+ </application>
+ </manifest>
+ """
+ ).indented()
+
+ /* ktlint-disable max-line-length */
+ lint().files(
+ // Manifest file
+ manifestWithInitializer,
+ // Source files
+ ANDROID_APPLICATION,
+ WORK_MANAGER_CONFIGURATION_PROVIDER,
+ customApplication
+ )
+ .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+ .run()
+ .expect("""
+ AndroidManifest.xml:5: Error: Remove androidx.work.impl.WorkManagerInitializer from your AndroidManifest.xml when using on-demand initialization. [RemoveWorkManagerInitializer]
+ <provider
+ ^
+ 1 errors, 0 warnings
+ """.trimIndent())
+ /* ktlint-enable max-line-length */
+ }
+}