Merge "Update nav compose to navigation-runtime 2.3.1" into androidx-master-dev
diff --git a/buildSrc/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt b/buildSrc/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
index 7042a64..f88c50d 100644
--- a/buildSrc/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/uptodatedness/TaskUpToDateValidator.kt
@@ -46,9 +46,7 @@
"createProjectZip",
"desugarPublicDebugFileDependencies",
"desugarTipOfTreeDebugFileDependencies",
- "distPublicDokkaDocs",
- "dokkaJavaPublicDocs",
- "dokkaKotlinPublicDocs",
+ "dokkaKotlinDocs",
"externalNativeBuildDebug",
"externalNativeBuildRelease",
"generateJsonModelDebug",
@@ -89,10 +87,10 @@
"stripArchiveForPartialDejetification",
"transformClassesWithDexBuilderForPublicDebug",
"transformClassesWithDexBuilderForTipOfTreeDebug",
- "unzipDokkaPublicDocsDeps",
"verifyDependencyVersions",
"zipEcFiles",
"zipTestConfigsWithApks",
+ "zipDokkaDocs",
":camera:integration-tests:camera-testapp-core:mergeLibDexDebug",
":camera:integration-tests:camera-testapp-core:packageDebug",
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
index 987a8af..5b24ca5 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/CameraControllerDeviceTest.kt
@@ -118,4 +118,25 @@
ContentValues()
)
}
+
+ @UiThreadTest
+ @Test
+ public fun analysisIsEnabledByDefault() {
+ assertThat(controller.isImageAnalysisEnabled).isTrue()
+ }
+
+ @UiThreadTest
+ @Test
+ public fun captureIsEnabledByDefault() {
+ assertThat(controller.isImageCaptureEnabled).isTrue()
+ }
+
+ @UiThreadTest
+ @Test
+ public fun disableAnalysisCaptureEnableVideo() {
+ controller.setEnabledUseCases(CameraController.VIDEO_CAPTURE)
+ assertThat(controller.isImageCaptureEnabled).isFalse()
+ assertThat(controller.isImageAnalysisEnabled).isFalse()
+ assertThat(controller.isVideoCaptureEnabled).isTrue()
+ }
}
\ No newline at end of file
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index 6c64e5f..a88f629 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -103,8 +103,28 @@
private static final float AF_SIZE = 1.0f / 6.0f;
private static final float AE_SIZE = AF_SIZE * 1.5f;
+ /**
+ * Bitmask option to enable {@link android.media.Image}. In {@link #setEnabledUseCases}, if
+ * (enabledUseCases & IMAGE_CAPTURE) != 0, then controller will enable image capture features.
+ */
+ public static int IMAGE_CAPTURE = 0b1;
+ /**
+ * Bitmask option to enable {@link ImageAnalysis}. In {@link #setEnabledUseCases}, if
+ * (enabledUseCases & IMAGE_ANALYSIS) != 0, then controller will enable image analysis features.
+ */
+ public static int IMAGE_ANALYSIS = 0b10;
+ /**
+ * Bitmask option to enable video capture use case. In {@link #setEnabledUseCases}, if
+ * (enabledUseCases & VIDEO_CAPTURE) != 0, then controller will enable video capture features.
+ */
+ @ExperimentalVideo
+ public static int VIDEO_CAPTURE = 0b100;
+
CameraSelector mCameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
+ // By default, ImageCapture and ImageAnalysis are enabled. VideoCapture is disabled.
+ private int mEnabledUseCases = IMAGE_CAPTURE | IMAGE_ANALYSIS;
+
// CameraController and PreviewView hold reference to each other. The 2-way link is managed
// by PreviewView.
// Synthetic access
@@ -117,12 +137,6 @@
@NonNull
final ImageCapture mImageCapture;
- // ImageCapture is enabled by default.
- private boolean mImageCaptureEnabled = true;
-
- // ImageAnalysis is enabled by default.
- private boolean mImageAnalysisEnabled = true;
-
@Nullable
private Executor mAnalysisExecutor;
@@ -137,9 +151,6 @@
@NonNull
final VideoCapture mVideoCapture;
- // VideoCapture is disabled by default.
- private boolean mVideoCaptureEnabled = false;
-
// Synthetic access
@SuppressWarnings("WeakerAccess")
@NonNull
@@ -258,6 +269,78 @@
return mCamera != null;
}
+ /**
+ * Enables or disables use cases.
+ *
+ * <p> Use cases need to be enabled before they can be used. By default, {@link #IMAGE_CAPTURE}
+ * and {@link #IMAGE_ANALYSIS} are enabled, and {@link #VIDEO_CAPTURE} is disabled. This is
+ * necessary because {@link #VIDEO_CAPTURE} is an experimental feature that might not work
+ * with other use cases, especially on lower end devices. When that happens, this method will
+ * fail with an {@link IllegalStateException}.
+ *
+ * <p> To make sure {@link #VIDEO_CAPTURE} works, {@link #IMAGE_CAPTURE} and
+ * {@link #IMAGE_ANALYSIS} needs to be disabled when enabling {@link #VIDEO_CAPTURE}. For
+ * example:
+ *
+ * <pre><code>
+ * // By default, image capture is enabled. Taking picture works.
+ * controller.takePicture(...);
+ *
+ * // Switch to video capture to shoot video.
+ * controller.setEnabledUseCases(VIDEO_CAPTURE);
+ * controller.startRecording(...);
+ * controller.stopRecording(...);
+ *
+ * // Switch back to image capture and image analysis before taking another picture.
+ * controller.setEnabledUseCases(IMAGE_CAPTURE|IMAGE_ANALYSIS);
+ * controller.takePicture(...);
+ *
+ * </code></pre>
+ *
+ * @param enabledUseCases one or more of the following use cases, bitwise-OR-ed together:
+ * {@link #IMAGE_CAPTURE}, {@link #IMAGE_ANALYSIS} and/or
+ * {@link #VIDEO_CAPTURE}.
+ * @throws IllegalStateException If the current camera selector is unable to resolve a
+ * camera to be used for the enabled use cases.
+ * @see UseCase
+ * @see ImageCapture
+ * @see ImageAnalysis
+ */
+ @UseExperimental(markerClass = ExperimentalVideo.class)
+ public void setEnabledUseCases(int enabledUseCases) {
+ if (enabledUseCases == mEnabledUseCases) {
+ return;
+ }
+ int oldEnabledUseCases = mEnabledUseCases;
+ mEnabledUseCases = enabledUseCases;
+ if (!isVideoCaptureEnabled()) {
+ stopRecording();
+ }
+ startCameraAndTrackStates(() -> mEnabledUseCases = oldEnabledUseCases);
+ }
+
+ /**
+ * Checks if the given use case mask is enabled.
+ *
+ * @param useCaseMask One of the {@link #IMAGE_CAPTURE}, {@link #IMAGE_ANALYSIS} or
+ * {@link #VIDEO_CAPTURE}
+ * @return true if the use case is enabled.
+ */
+ private boolean isUseCaseEnabled(int useCaseMask) {
+ return (mEnabledUseCases & useCaseMask) != 0;
+ }
+
+ /**
+ * Same as {@link #isVideoCaptureEnabled()}.
+ *
+ * <p> This wrapper method is to workaround the limitation that currently only one
+ * {@link UseExperimental} mark class is allowed per method.
+ */
+ @UseExperimental(markerClass = ExperimentalVideo.class)
+ private boolean isVideoCaptureEnabledInternal() {
+ return isVideoCaptureEnabled();
+ }
+
// ------------------
// Preview use case.
// ------------------
@@ -331,28 +414,7 @@
@MainThread
public boolean isImageCaptureEnabled() {
Threads.checkMainThread();
- return mImageCaptureEnabled;
- }
-
- /**
- * Enables or disables {@link ImageCapture}.
- *
- * <p> {@link ImageCapture} might not work with video capture depending on device
- * limitations. In that case, the method will fail with {@link IllegalStateException}.
- *
- * @throws IllegalArgumentException If the current camera selector is unable to resolve a
- * camera to be used for the enabled use cases.
- * @see ImageCapture
- */
- @MainThread
- public void setImageCaptureEnabled(boolean imageCaptureEnabled) {
- Threads.checkMainThread();
- if (mImageCaptureEnabled == imageCaptureEnabled) {
- return;
- }
- boolean oldImageCaptureEnabled = mImageCaptureEnabled;
- mImageCaptureEnabled = imageCaptureEnabled;
- startCameraAndTrackStates(() -> mImageAnalysisEnabled = oldImageCaptureEnabled);
+ return isUseCaseEnabled(IMAGE_CAPTURE);
}
/**
@@ -405,7 +467,7 @@
@NonNull ImageCapture.OnImageSavedCallback imageSavedCallback) {
Threads.checkMainThread();
Preconditions.checkState(isCameraInitialized(), CAMERA_NOT_INITIALIZED);
- Preconditions.checkState(mImageCaptureEnabled, IMAGE_CAPTURE_DISABLED);
+ Preconditions.checkState(isImageCaptureEnabled(), IMAGE_CAPTURE_DISABLED);
updateMirroringFlagInOutputFileOptions(outputFileOptions);
mImageCapture.takePicture(outputFileOptions, executor, imageSavedCallback);
@@ -445,7 +507,7 @@
@NonNull ImageCapture.OnImageCapturedCallback callback) {
Threads.checkMainThread();
Preconditions.checkState(isCameraInitialized(), CAMERA_NOT_INITIALIZED);
- Preconditions.checkState(mImageCaptureEnabled, IMAGE_CAPTURE_DISABLED);
+ Preconditions.checkState(isImageCaptureEnabled(), IMAGE_CAPTURE_DISABLED);
mImageCapture.takePicture(executor, callback);
}
@@ -462,28 +524,7 @@
@MainThread
public boolean isImageAnalysisEnabled() {
Threads.checkMainThread();
- return mImageAnalysisEnabled;
- }
-
- /**
- * Enables or disables {@link ImageAnalysis} use case.
- *
- * <p> {@link ImageAnalysis} might not work with video capture depending on device
- * limitations. In that case, the method will fail with {@link IllegalStateException}.
- *
- * @throws IllegalStateException If the current camera selector is unable to resolve a
- * camera to be used for the enabled use cases.
- * @see ImageAnalysis
- */
- @MainThread
- public void setImageAnalysisEnabled(boolean imageAnalysisEnabled) {
- Threads.checkMainThread();
- if (mImageAnalysisEnabled == imageAnalysisEnabled) {
- return;
- }
- boolean oldImageAnalysisEnabled = mImageAnalysisEnabled;
- mImageAnalysisEnabled = imageAnalysisEnabled;
- startCameraAndTrackStates(() -> mImageAnalysisEnabled = oldImageAnalysisEnabled);
+ return isUseCaseEnabled(IMAGE_ANALYSIS);
}
/**
@@ -630,32 +671,7 @@
@MainThread
public boolean isVideoCaptureEnabled() {
Threads.checkMainThread();
- return mVideoCaptureEnabled;
- }
-
- /**
- * Enables or disables video capture use case.
- *
- * <p> Due to hardware limitations, video capture might not work when {@link ImageAnalysis}
- * and/or {@link ImageCapture} is enabled. In that case, this method will fail with an
- * {@link IllegalStateException}.
- *
- * @throws IllegalStateException If the current camera selector is unable to resolve a
- * camera to be used for the enabled use cases.
- */
- @ExperimentalVideo
- @MainThread
- public void setVideoCaptureEnabled(boolean videoCaptureEnabled) {
- Threads.checkMainThread();
- if (mVideoCaptureEnabled == videoCaptureEnabled) {
- return;
- }
- if (!videoCaptureEnabled) {
- stopRecording();
- }
- boolean oldVideoCaptureEnabled = mVideoCaptureEnabled;
- mVideoCaptureEnabled = videoCaptureEnabled;
- startCameraAndTrackStates(() -> mVideoCaptureEnabled = oldVideoCaptureEnabled);
+ return isUseCaseEnabled(VIDEO_CAPTURE);
}
/**
@@ -671,7 +687,7 @@
@NonNull Executor executor, final @NonNull OnVideoSavedCallback callback) {
Threads.checkMainThread();
Preconditions.checkState(isCameraInitialized(), CAMERA_NOT_INITIALIZED);
- Preconditions.checkState(mVideoCaptureEnabled, VIDEO_CAPTURE_DISABLED);
+ Preconditions.checkState(isVideoCaptureEnabled(), VIDEO_CAPTURE_DISABLED);
mVideoCapture.startRecording(outputFileOptions.toVideoCaptureOutputFileOptions(), executor,
new VideoCapture.OnVideoSavedCallback() {
@@ -1041,19 +1057,19 @@
UseCaseGroup.Builder builder = new UseCaseGroup.Builder().addUseCase(mPreview);
- if (mImageCaptureEnabled) {
+ if (isImageCaptureEnabled()) {
builder.addUseCase(mImageCapture);
} else {
mCameraProvider.unbind(mImageCapture);
}
- if (mImageAnalysisEnabled) {
+ if (isImageAnalysisEnabled()) {
builder.addUseCase(mImageAnalysis);
} else {
mCameraProvider.unbind(mImageAnalysis);
}
- if (mVideoCaptureEnabled) {
+ if (isVideoCaptureEnabledInternal()) {
builder.addUseCase(mVideoCapture);
} else {
mCameraProvider.unbind(mVideoCapture);
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
index ce10c35..2b5868a 100644
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
@@ -120,9 +120,7 @@
val fragment = createFragmentScenario().getFragment()
fragment.assertAnalysisStreaming(true)
- instrumentation.runOnMainSync {
- fragment.cameraController.isImageAnalysisEnabled = false
- }
+ onView(withId(R.id.analysis_enabled)).perform(click())
fragment.assertAnalysisStreaming(false)
}
@@ -132,10 +130,8 @@
val fragment = createFragmentScenario().getFragment()
fragment.assertAnalysisStreaming(true)
- instrumentation.runOnMainSync {
- fragment.cameraController.isImageAnalysisEnabled = false
- fragment.cameraController.isImageAnalysisEnabled = true
- }
+ onView(withId(R.id.analysis_enabled)).perform(click())
+ onView(withId(R.id.analysis_enabled)).perform(click())
fragment.assertAnalysisStreaming(true)
}
@@ -156,7 +152,7 @@
fun canSetAnalysisImageDepth() {
// Arrange.
val fragment = createFragmentScenario().getFragment()
- var currentDepth: Int = 0
+ var currentDepth = 0
// Act.
instrumentation.runOnMainSync {
@@ -269,11 +265,11 @@
thrown.expectMessage("ImageCapture disabled")
val fragment = createFragmentScenario().getFragment()
fragment.assertPreviewIsStreaming()
- instrumentation.runOnMainSync {
- fragment.cameraController.isImageCaptureEnabled = false
- }
- // Act & assert.
+ // Act.
+ onView(withId(R.id.capture_enabled)).perform(click())
+
+ // Assert.
fragment.assertCanTakePicture()
}
@@ -284,10 +280,8 @@
fragment.assertPreviewIsStreaming()
// Act.
- instrumentation.runOnMainSync {
- fragment.cameraController.isImageCaptureEnabled = false
- fragment.cameraController.isImageCaptureEnabled = true
- }
+ onView(withId(R.id.capture_enabled)).perform(click())
+ onView(withId(R.id.capture_enabled)).perform(click())
fragment.assertPreviewIsStreaming()
// Assert.
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
index a7c83db..173165f 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
@@ -28,6 +28,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.SeekBar;
import android.widget.TextView;
@@ -47,6 +48,7 @@
import androidx.camera.core.impl.utils.executor.CameraXExecutors;
import androidx.camera.core.impl.utils.futures.FutureCallback;
import androidx.camera.core.impl.utils.futures.Futures;
+import androidx.camera.view.CameraController;
import androidx.camera.view.LifecycleCameraController;
import androidx.camera.view.PreviewView;
import androidx.camera.view.SensorRotationListener;
@@ -80,6 +82,8 @@
private Button mFlashMode;
private ToggleButton mCameraToggle;
private ExecutorService mExecutorService;
+ private ToggleButton mCaptureEnabledToggle;
+ private ToggleButton mAnalysisEnabledToggle;
private ToggleButton mVideoEnabledToggle;
private ToggleButton mPinchToZoomToggle;
private ToggleButton mTapToFocusToggle;
@@ -164,11 +168,9 @@
: CameraSelector.DEFAULT_FRONT_CAMERA)));
// Image Capture enable switch.
- ToggleButton captureEnabled = view.findViewById(R.id.capture_enabled);
- captureEnabled.setOnCheckedChangeListener(
- (compoundButton, value) -> runSafely(
- () -> mCameraController.setImageCaptureEnabled(value)));
- captureEnabled.setChecked(mCameraController.isImageCaptureEnabled());
+ mCaptureEnabledToggle = view.findViewById(R.id.capture_enabled);
+ mCaptureEnabledToggle.setOnCheckedChangeListener(this::onUseCaseToggled);
+ mCaptureEnabledToggle.setChecked(mCameraController.isImageCaptureEnabled());
// Flash mode for image capture.
mFlashMode = view.findViewById(R.id.flash_mode);
@@ -212,11 +214,10 @@
});
// Set up analysis UI.
- ToggleButton analysisEnabled = view.findViewById(R.id.analysis_enabled);
- analysisEnabled.setOnCheckedChangeListener(
- (compoundButton, value) ->
- runSafely(() -> mCameraController.setImageAnalysisEnabled(value)));
- analysisEnabled.setChecked(mCameraController.isImageAnalysisEnabled());
+ mAnalysisEnabledToggle = view.findViewById(R.id.analysis_enabled);
+ mAnalysisEnabledToggle.setOnCheckedChangeListener(
+ this::onUseCaseToggled);
+ mAnalysisEnabledToggle.setChecked(mCameraController.isImageAnalysisEnabled());
ToggleButton analyzerSet = view.findViewById(R.id.analyzer_set);
analyzerSet.setOnCheckedChangeListener(
@@ -233,7 +234,7 @@
mVideoEnabledToggle = view.findViewById(R.id.video_enabled);
mVideoEnabledToggle.setOnCheckedChangeListener(
(compoundButton, checked) -> {
- runSafely(() -> mCameraController.setVideoCaptureEnabled(checked));
+ onUseCaseToggled(compoundButton, checked);
updateUiText();
});
@@ -425,6 +426,26 @@
}
}
+ @UseExperimental(markerClass = ExperimentalVideo.class)
+ private void onUseCaseToggled(CompoundButton compoundButton, boolean value) {
+ if (mCaptureEnabledToggle == null || mAnalysisEnabledToggle == null
+ || mVideoEnabledToggle == null) {
+ return;
+ }
+ int useCaseEnabledFlags = 0;
+ if (mCaptureEnabledToggle.isChecked()) {
+ useCaseEnabledFlags = useCaseEnabledFlags | CameraController.IMAGE_CAPTURE;
+ }
+ if (mAnalysisEnabledToggle.isChecked()) {
+ useCaseEnabledFlags = useCaseEnabledFlags | CameraController.IMAGE_ANALYSIS;
+ }
+ if (mVideoEnabledToggle.isChecked()) {
+ useCaseEnabledFlags = useCaseEnabledFlags | CameraController.VIDEO_CAPTURE;
+ }
+ final int finalUseCaseEnabledFlags = useCaseEnabledFlags;
+ runSafely(() -> mCameraController.setEnabledUseCases(finalUseCaseEnabledFlags));
+ }
+
// -----------------
// For testing
// -----------------
diff --git a/compose/foundation/foundation-text/api/current.txt b/compose/foundation/foundation-text/api/current.txt
index d699196..5b05f0e 100644
--- a/compose/foundation/foundation-text/api/current.txt
+++ b/compose/foundation/foundation-text/api/current.txt
@@ -2,7 +2,7 @@
package androidx.compose.foundation.text {
public final class CoreTextFieldKt {
- method @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void CoreTextField-wQ2hrV0(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
+ method @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void CoreTextField-dSfP_Go(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
method @Deprecated @VisibleForTesting public static void setBlinkingCursorEnabled(boolean p);
}
diff --git a/compose/foundation/foundation-text/api/public_plus_experimental_current.txt b/compose/foundation/foundation-text/api/public_plus_experimental_current.txt
index d699196..5b05f0e 100644
--- a/compose/foundation/foundation-text/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation-text/api/public_plus_experimental_current.txt
@@ -2,7 +2,7 @@
package androidx.compose.foundation.text {
public final class CoreTextFieldKt {
- method @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void CoreTextField-wQ2hrV0(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
+ method @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void CoreTextField-dSfP_Go(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
method @Deprecated @VisibleForTesting public static void setBlinkingCursorEnabled(boolean p);
}
diff --git a/compose/foundation/foundation-text/api/restricted_current.txt b/compose/foundation/foundation-text/api/restricted_current.txt
index d699196..5b05f0e 100644
--- a/compose/foundation/foundation-text/api/restricted_current.txt
+++ b/compose/foundation/foundation-text/api/restricted_current.txt
@@ -2,7 +2,7 @@
package androidx.compose.foundation.text {
public final class CoreTextFieldKt {
- method @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void CoreTextField-wQ2hrV0(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.ui.text.input.KeyboardType keyboardType, optional androidx.compose.ui.text.input.ImeAction imeAction, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
+ method @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void CoreTextField-dSfP_Go(androidx.compose.ui.text.input.TextFieldValue value, optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.text.TextStyle textStyle, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted, optional long cursorColor, optional boolean softWrap, optional int maxLines, optional androidx.compose.ui.text.input.KeyboardOptions keyboardOptions);
method @Deprecated @VisibleForTesting public static void setBlinkingCursorEnabled(boolean p);
}
diff --git a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelection.kt b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelection.kt
index 8e24042..a747bfc 100644
--- a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelection.kt
+++ b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelection.kt
@@ -23,12 +23,9 @@
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.selection.DisableSelection
-import androidx.compose.ui.selection.Selection
import androidx.compose.ui.selection.SelectionContainer
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
@@ -54,13 +51,9 @@
@Composable
fun TextDemoSelection() {
- val selection = remember { mutableStateOf<Selection?>(null) }
val arabicSentence =
"\nكلمة شين في قاموس المعاني الفوري مجال البحث مصطلحات المعجم الوسيط ،اللغة"
- SelectionContainer(
- selection = selection.value,
- selection.value = it }
- ) {
+ SelectionContainer {
Text(
style = TextStyle(
color = Color(0xFFFF0000),
@@ -100,11 +93,7 @@
@Composable
fun TextDemoSelectionWithStringInput() {
- val selection = remember { mutableStateOf<Selection?>(null) }
- SelectionContainer(
- selection = selection.value,
- selection.value = it }
- ) {
+ SelectionContainer {
Text(
text = "$displayText $displayTextChinese $displayTextHindi",
color = Color(0xFFFF0000),
@@ -134,11 +123,7 @@
Color(0xFFFF0000)
)
- val selection = remember { mutableStateOf<Selection?>(null) }
- SelectionContainer(
- selection = selection.value,
- selection.value = it }
- ) {
+ SelectionContainer {
Column(Modifier.fillMaxHeight()) {
for (i in 0..2) {
Row(Modifier.fillMaxWidth()) {
@@ -163,12 +148,7 @@
val textSelectable = "This text is selectable."
val textNotSelectable = "This text is not selectable."
- val selection = remember { mutableStateOf<Selection?>(null) }
-
- SelectionContainer(
- selection = selection.value,
- selection.value = it }
- ) {
+ SelectionContainer {
Column(Modifier.fillMaxHeight()) {
Text(
text = textSelectable,
diff --git a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelectionSample.kt b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelectionSample.kt
index f9f94a8..3674cf1 100644
--- a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelectionSample.kt
+++ b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/ComposeTextSelectionSample.kt
@@ -25,11 +25,8 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.preferredSize
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.selection.Selection
import androidx.compose.ui.selection.SelectionContainer
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
@@ -74,12 +71,8 @@
@Composable
fun TextSelectionSample() {
- val selection = remember { mutableStateOf<Selection?>(null) }
ScrollableColumn {
- SelectionContainer(
- selection = selection.value,
- selection.value = it }
- ) {
+ SelectionContainer {
Column(Modifier.padding(12.dp)) {
Basics()
AddTextElement()
diff --git a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/KeyboardOptionsDemo.kt b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/KeyboardOptionsDemo.kt
index e9b17f2..26f0042 100644
--- a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/KeyboardOptionsDemo.kt
+++ b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/src/main/java/androidx/compose/foundation/text/demos/KeyboardOptionsDemo.kt
@@ -39,62 +39,80 @@
@OptIn(ExperimentalTextApi::class)
private class KeyboardOptionsData(
val keyboardOptions: KeyboardOptions,
- val keyboardType: KeyboardType,
val name: String,
- val imeAction: ImeAction = ImeAction.Unspecified
)
@OptIn(ExperimentalTextApi::class)
private val KeyboardOptionsList = listOf(
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(singleLine = true),
- keyboardType = KeyboardType.Text,
+ keyboardOptions = KeyboardOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Text
+ ),
name = "singleLine/Text"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(singleLine = false),
- keyboardType = KeyboardType.Text,
+ keyboardOptions = KeyboardOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Text
+ ),
name = "multiLine/Text"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(singleLine = true),
- keyboardType = KeyboardType.Text,
- imeAction = ImeAction.Search,
+ keyboardOptions = KeyboardOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Search
+ ),
name = "singleLine/Text/Search"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(singleLine = true),
- keyboardType = KeyboardType.Number,
+ keyboardOptions = KeyboardOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Number
+ ),
name = "singleLine/Number"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(singleLine = false),
- keyboardType = KeyboardType.Number,
+ keyboardOptions = KeyboardOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Number
+ ),
name = "multiLine/Number"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Characters),
- keyboardType = KeyboardType.Text,
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Characters,
+ keyboardType = KeyboardType.Text
+ ),
name = "Capitalize Characters"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Words),
- keyboardType = KeyboardType.Text,
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Words,
+ keyboardType = KeyboardType.Text
+ ),
name = "Capitalize Words"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
- keyboardType = KeyboardType.Text,
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Text
+ ),
name = "Capitalize Sentences"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(autoCorrect = true),
- keyboardType = KeyboardType.Text,
+ keyboardOptions = KeyboardOptions(
+ autoCorrect = true,
+ keyboardType = KeyboardType.Text
+ ),
name = "AutoCorrect On"
),
KeyboardOptionsData(
- keyboardOptions = KeyboardOptions(autoCorrect = false),
- keyboardType = KeyboardType.Text,
+ keyboardOptions = KeyboardOptions(
+ autoCorrect = false,
+ keyboardType = KeyboardType.Text
+ ),
name = "AutoCorrect Off"
)
)
@@ -122,8 +140,6 @@
CoreTextField(
modifier = demoTextFieldModifiers.defaultMinSizeConstraints(100.dp),
value = state.value,
- keyboardType = data.keyboardType,
- imeAction = data.imeAction,
keyboardOptions = data.keyboardOptions,
state.value = it },
textStyle = TextStyle(fontSize = fontSize8),
diff --git a/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt b/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
index 31bfb8a..e0ec19b 100644
--- a/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
+++ b/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/CoreTextFieldInputServiceIntegrationTest.kt
@@ -69,18 +69,17 @@
val keyboardOptions = KeyboardOptions(
singleLine = true,
capitalization = KeyboardCapitalization.Words,
- autoCorrect = false
+ autoCorrect = false,
+ keyboardType = KeyboardType.Phone,
+ imeAction = ImeAction.Search
)
- val keyboardType = KeyboardType.Phone
- val imeAction = ImeAction.Search
+
var focused = false
rule.setContent {
CoreTextField(
value = value,
keyboardOptions = keyboardOptions,
- keyboardType = keyboardType,
- imeAction = imeAction,
modifier = Modifier
.testTag(testTag)
.focusObserver { focused = it.isFocused },
@@ -95,8 +94,6 @@
verify(platformTextInputService, times(1)).startInput(
eq(value),
- eq(keyboardType),
- eq(imeAction),
eq(keyboardOptions),
any(), // onEditCommand
any() // onImeActionPerformed
diff --git a/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/SelectionContainerTest.kt b/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/SelectionContainerTest.kt
index ea848c5..3ba2377 100644
--- a/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/SelectionContainerTest.kt
+++ b/compose/foundation/foundation-text/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/selection/SelectionContainerTest.kt
@@ -44,6 +44,7 @@
import androidx.compose.ui.selection.SelectionContainer
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
@@ -75,6 +76,8 @@
import kotlin.math.max
import kotlin.math.roundToInt
+@Suppress("DEPRECATION")
+@OptIn(InternalTextApi::class)
@LargeTest
@RunWith(AndroidJUnit4::class)
class SelectionContainerTest {
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index bc7c859..b1a5ce0 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -93,7 +93,6 @@
import androidx.compose.ui.text.input.EditProcessor
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardOptions
-import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.NO_SESSION
import androidx.compose.ui.text.input.OffsetMap
import androidx.compose.ui.text.input.TextFieldValue
@@ -129,13 +128,6 @@
* @param onValueChange Called when the input service updates the values in [TextFieldValue].
* @param modifier optional [Modifier] for this text field.
* @param textStyle Style configuration that applies at character level such as color, font etc.
- * @param keyboardType The keyboard type to be used in this text field. Note that this input type
- * is honored by IME and shows corresponding keyboard but this is not guaranteed. For example,
- * some IME may send non-ASCII character even if you set [KeyboardType.Ascii].
- * @param imeAction The IME action. This IME action is honored by IME and may show specific icons
- * on the keyboard. For example, search icon may be shown if [ImeAction.Search] is specified.
- * Then, when user tap that key, the [onImeActionPerformed] callback is called with specified
- * ImeAction.
* @param onImeActionPerformed Called when the input service requested an IME action. When the
* input service emitted an IME action, this callback is called with the emitted IME action. Note
* that this IME action may be different from what you specified in [imeAction].
@@ -163,8 +155,6 @@
modifier: Modifier = Modifier,
onValueChange: (TextFieldValue) -> Unit,
textStyle: TextStyle = TextStyle.Default,
- keyboardType: KeyboardType = KeyboardType.Text,
- imeAction: ImeAction = ImeAction.Unspecified,
onImeActionPerformed: (ImeAction) -> Unit = {},
visualTransformation: VisualTransformation = VisualTransformation.None,
onTextLayout: (TextLayoutResult) -> Unit = {},
@@ -247,8 +237,6 @@
textInputService,
value,
state.processor,
- keyboardType,
- imeAction,
keyboardOptions,
onValueChangeWrapper,
onImeActionPerformedWrapper
@@ -361,7 +349,7 @@
}
val semanticsModifier = Modifier.semantics {
- this.imeAction = imeAction
+ this.imeAction = keyboardOptions.imeAction
this.supportsInputMethods()
this.text = AnnotatedString(value.text)
this.textSelectionRange = value.selection
@@ -428,8 +416,7 @@
}
}
- val cursorModifier =
- Modifier.cursor(state, value, offsetMap, cursorColor)
+ val cursorModifier = Modifier.cursor(state, value, offsetMap, cursorColor)
onDispose { manager.hideSelectionToolbar() }
@@ -471,9 +458,10 @@
if (state.hasFocus && state.selectionIsOn) {
manager.state?.layoutResult?.let {
if (!value.selection.collapsed) {
- val startDirection = it.getBidiRunDirection(value.selection.start)
- val endDirection =
- it.getBidiRunDirection(max(value.selection.end - 1, 0))
+ val startOffset = offsetMap.originalToTransformed(value.selection.start)
+ val endOffset = offsetMap.originalToTransformed(value.selection.end)
+ val startDirection = it.getBidiRunDirection(startOffset)
+ val endDirection = it.getBidiRunDirection(max(endOffset - 1, 0))
val directions = Pair(startDirection, endDirection)
TextFieldSelectionHandle(
isStartHandle = true,
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
index 7c22f19..33dca06 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
@@ -41,7 +41,6 @@
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.InputSessionToken
import androidx.compose.ui.text.input.KeyboardOptions
-import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.OffsetMap
import androidx.compose.ui.text.input.SetSelectionEditOp
import androidx.compose.ui.text.input.TextFieldValue
@@ -316,25 +315,21 @@
* @param textInputService The text input service
* @param value The editor state
* @param editProcessor The edit processor
- * @param keyboardType The keyboard type
* @param onValueChange The callback called when the new editor state arrives.
* @param onImeActionPerformed The callback called when the editor action arrives.
+ * @param keyboardOptions Keyboard configuration such as single line, auto correct etc.
*/
@JvmStatic
internal fun onFocus(
textInputService: TextInputService?,
value: TextFieldValue,
editProcessor: EditProcessor,
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
onValueChange: (TextFieldValue) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
): InputSessionToken {
val inputSessionToken = textInputService?.startInput(
value = TextFieldValue(value.text, value.selection, value.composition),
- keyboardType = keyboardType,
- imeAction = imeAction,
keyboardOptions = keyboardOptions,
onEditCommand(it, editProcessor, onValueChange) },
>
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
index acd8264..61e66f9 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
@@ -34,6 +34,7 @@
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.constrain
import androidx.compose.ui.text.input.OffsetMap
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.getSelectedText
@@ -123,7 +124,7 @@
)
hapticFeedBack?.performHapticFeedback(HapticFeedbackType.TextHandleMove)
- val newValue = TextFieldValue(
+ val newValue = createTextFieldValue(
text = value.text,
selection = TextRange(offset, offset)
)
@@ -137,13 +138,11 @@
if (value.text == "") return
enterSelectionMode()
state?.layoutResult?.let { layoutResult ->
- val offset = offsetMap.transformedToOriginal(
- layoutResult.getOffsetForPosition(pxPosition)
- )
+ val offset = layoutResult.getOffsetForPosition(pxPosition)
updateSelection(
value = value,
- startOffset = offset,
- endOffset = offset,
+ transformedStartOffset = offset,
+ transformedEndOffset = offset,
isStartHandle = true,
wordBasedSelection = true
)
@@ -159,12 +158,13 @@
dragTotalDistance += dragDistance
state?.layoutResult?.let { layoutResult ->
val startOffset = layoutResult.getOffsetForPosition(dragBeginPosition)
- val endOffset =
- layoutResult.getOffsetForPosition(dragBeginPosition + dragTotalDistance)
+ val endOffset = layoutResult.getOffsetForPosition(
+ dragBeginPosition + dragTotalDistance
+ )
updateSelection(
value = value,
- startOffset = startOffset,
- endOffset = endOffset,
+ transformedStartOffset = startOffset,
+ transformedEndOffset = endOffset,
isStartHandle = true,
wordBasedSelection = true
)
@@ -199,22 +199,20 @@
dragTotalDistance += dragDistance
state?.layoutResult?.let { layoutResult ->
- val startOffset =
- if (isStartHandle)
- layoutResult.getOffsetForPosition(dragBeginPosition + dragTotalDistance)
- else
- value.selection.start
+ val startOffset = if (isStartHandle)
+ layoutResult.getOffsetForPosition(dragBeginPosition + dragTotalDistance)
+ else
+ offsetMap.originalToTransformed(value.selection.start)
- val endOffset =
- if (isStartHandle)
- value.selection.end
- else
- layoutResult.getOffsetForPosition(dragBeginPosition + dragTotalDistance)
+ val endOffset = if (isStartHandle)
+ offsetMap.originalToTransformed(value.selection.end)
+ else
+ layoutResult.getOffsetForPosition(dragBeginPosition + dragTotalDistance)
updateSelection(
value = value,
- startOffset = startOffset,
- endOffset = endOffset,
+ transformedStartOffset = startOffset,
+ transformedEndOffset = endOffset,
isStartHandle = isStartHandle,
wordBasedSelection = false
)
@@ -275,10 +273,11 @@
internal fun copy() {
if (value.selection.collapsed) return
+ // TODO(b/171947959) check if original or transformed should be copied
clipboardManager?.setText(AnnotatedString(value.getSelectedText()))
val newCursorOffset = value.selection.max
- val newValue = TextFieldValue(
+ val newValue = createTextFieldValue(
text = value.text,
selection = TextRange(newCursorOffset, newCursorOffset)
)
@@ -303,7 +302,7 @@
value.getTextAfterSelection(value.text.length)
val newCursorOffset = value.selection.min + text.length
- val newValue = TextFieldValue(
+ val newValue = createTextFieldValue(
text = newText,
selection = TextRange(newCursorOffset, newCursorOffset)
)
@@ -323,13 +322,14 @@
internal fun cut() {
if (value.selection.collapsed) return
+ // TODO(b/171947959) check if original or transformed should be cut
clipboardManager?.setText(AnnotatedString(value.getSelectedText()))
val newText = value.getTextBeforeSelection(value.text.length) +
value.getTextAfterSelection(value.text.length)
val newCursorOffset = value.selection.min
- val newValue = TextFieldValue(
+ val newValue = createTextFieldValue(
text = newText,
selection = TextRange(newCursorOffset, newCursorOffset)
)
@@ -341,7 +341,7 @@
internal fun selectAll() {
setSelectionStatus(true)
- val newValue = TextFieldValue(
+ val newValue = createTextFieldValue(
text = value.text,
selection = TextRange(0, value.text.length)
)
@@ -352,14 +352,14 @@
return if (isStartHandle)
getSelectionHandleCoordinates(
textLayoutResult = state?.layoutResult!!,
- offset = value.selection.start,
+ offset = offsetMap.originalToTransformed(value.selection.start),
isStart = true,
areHandlesCrossed = value.selection.reversed
)
else
getSelectionHandleCoordinates(
textLayoutResult = state?.layoutResult!!,
- offset = value.selection.end,
+ offset = offsetMap.originalToTransformed(value.selection.end),
isStart = false,
areHandlesCrossed = value.selection.reversed
)
@@ -471,28 +471,38 @@
private fun updateSelection(
value: TextFieldValue,
- startOffset: Int,
- endOffset: Int,
+ transformedStartOffset: Int,
+ transformedEndOffset: Int,
isStartHandle: Boolean,
wordBasedSelection: Boolean
) {
- val range = getTextFieldSelection(
+ val transformedSelection = TextRange(
+ offsetMap.originalToTransformed(value.selection.start),
+ offsetMap.originalToTransformed(value.selection.end)
+ )
+
+ val newTransformedSelection = getTextFieldSelection(
textLayoutResult = state?.layoutResult,
- rawStartOffset = startOffset,
- rawEndOffset = endOffset,
- previousSelection = if (value.selection.collapsed) null else value.selection,
- previousHandlesCrossed = value.selection.reversed,
+ rawStartOffset = transformedStartOffset,
+ rawEndOffset = transformedEndOffset,
+ previousSelection = if (transformedSelection.collapsed) null else transformedSelection,
+ previousHandlesCrossed = transformedSelection.reversed,
isStartHandle = isStartHandle,
wordBasedSelection = wordBasedSelection
)
- if (range == value.selection) return
+ val originalSelection = TextRange(
+ start = offsetMap.transformedToOriginal(newTransformedSelection.start),
+ end = offsetMap.transformedToOriginal(newTransformedSelection.end)
+ )
+
+ if (originalSelection == value.selection) return
hapticFeedBack?.performHapticFeedback(HapticFeedbackType.TextHandleMove)
- val newValue = TextFieldValue(
+ val newValue = createTextFieldValue(
text = value.text,
- selection = range
+ selection = originalSelection
)
onValueChange(newValue)
}
@@ -503,6 +513,13 @@
}
}
+ private fun createTextFieldValue(
+ text: String,
+ selection: TextRange,
+ ): TextFieldValue {
+ return TextFieldValue(text = text, selection = selection.constrain(0, text.length))
+ }
+
/** Returns true if the screen coordinates position (x,y) corresponds to a character displayed
* in the view. Returns false when the position is in the empty space of left/right of text.
*/
diff --git a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
index 1ab27c5..5f54d28 100644
--- a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
+++ b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/TextFieldDelegateTest.kt
@@ -159,17 +159,15 @@
val editorState = TextFieldValue(text = "Hello, World", selection = TextRange(1))
val keyboardOptions = KeyboardOptions(
singleLine = true,
- capitalization = KeyboardCapitalization.Sentences
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Phone,
+ imeAction = ImeAction.Search
)
- val keyboardType = KeyboardType.Phone
- val imeAction = ImeAction.Search
TextFieldDelegate.onFocus(
textInputService = textInputService,
value = editorState,
editProcessor = processor,
- keyboardType = keyboardType,
- imeAction = imeAction,
keyboardOptions = keyboardOptions,
>
>
@@ -181,8 +179,6 @@
selection = editorState.selection
)
),
- eq(keyboardType),
- eq(imeAction),
eq(keyboardOptions),
any(),
eq(onEditorActionPerformed)
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt
index e0c786e..08b0281 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/SoftwareKeyboardTest.kt
@@ -52,7 +52,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any()))
.thenReturn(inputSessionToken)
val onTextInputStarted: (SoftwareKeyboardController) -> Unit = mock()
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt
index 84d7f48..a4ecfbc 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldOnValueChangeTextFieldValueTest.kt
@@ -67,7 +67,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any()))
.thenReturn(inputSessionToken)
rule.setContent {
@@ -101,8 +101,6 @@
val -> Unit>()
verify(textInputService, times(1)).startInput(
value = any(),
- keyboardType = any(),
- imeAction = any(),
keyboardOptions = any(),
>
>
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt
index 89e2d9b..20822be 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/TextFieldTest.kt
@@ -148,7 +148,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any()))
.thenReturn(inputSessionToken)
rule.setContent {
@@ -167,8 +167,6 @@
val -> Unit>()
verify(textInputService, times(1)).startInput(
value = any(),
- keyboardType = any(),
- imeAction = any(),
keyboardOptions = any(),
>
>
@@ -221,7 +219,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any()))
.thenReturn(inputSessionToken)
rule.setContent {
@@ -240,8 +238,6 @@
val -> Unit>()
verify(textInputService, times(1)).startInput(
value = any(),
- keyboardType = any(),
- imeAction = any(),
keyboardOptions = any(),
>
>
@@ -281,7 +277,7 @@
val textInputService = mock<TextInputService>()
val inputSessionToken = 10 // any positive number is fine.
- whenever(textInputService.startInput(any(), any(), any(), any(), any(), any()))
+ whenever(textInputService.startInput(any(), any(), any(), any()))
.thenReturn(inputSessionToken)
val onTextLayout: (TextLayoutResult) -> Unit = mock()
@@ -309,8 +305,6 @@
val -> Unit>()
verify(textInputService, times(1)).startInput(
value = any(),
- keyboardType = any(),
- imeAction = any(),
keyboardOptions = any(),
>
>
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
index cbf9393..38feffc 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicTextField.kt
@@ -23,6 +23,7 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.InternalTextApi
import androidx.compose.ui.text.SoftwareKeyboardController
import androidx.compose.ui.text.TextLayoutResult
@@ -30,6 +31,7 @@
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.constrain
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
@@ -189,7 +191,7 @@
* @param cursorColor Color of the cursor. If [Color.Unspecified], there will be no cursor drawn
*/
@Composable
-@OptIn(InternalTextApi::class)
+@OptIn(InternalTextApi::class, ExperimentalTextApi::class)
fun BasicTextField(
value: TextFieldValue,
onValueChange: (TextFieldValue) -> Unit,
@@ -204,16 +206,18 @@
cursorColor: Color = Color.Black
) {
CoreTextField(
- value,
- modifier,
- onValueChange,
- textStyle,
- keyboardType,
- imeAction,
- onImeActionPerformed,
- visualTransformation,
- onTextLayout,
- onTextInputStarted,
- cursorColor
+ value = value,
+ modifier = modifier,
+ >
+ textStyle = textStyle,
+ >
+ visualTransformation = visualTransformation,
+ >
+ >
+ cursorColor = cursorColor,
+ keyboardOptions = KeyboardOptions(
+ keyboardType = keyboardType,
+ imeAction = imeAction
+ ),
)
}
\ No newline at end of file
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt
index d2e4968..8229da8 100644
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt
+++ b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/text/TextFieldToggleTextTestCase.kt
@@ -37,7 +37,6 @@
import androidx.compose.ui.text.input.EditOperation
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardOptions
-import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.TextInputService
@@ -105,8 +104,6 @@
private class TestPlatformTextInputService : PlatformTextInputService {
override fun startInput(
value: TextFieldValue,
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
diff --git a/compose/material/material/build.gradle b/compose/material/material/build.gradle
index f9b13d4..84baf44 100644
--- a/compose/material/material/build.gradle
+++ b/compose/material/material/build.gradle
@@ -149,9 +149,6 @@
// Screenshot tests related setup
android {
- defaultConfig {
- testInstrumentationRunnerArgument("thisisignored", "thisisignored --no-isolated-storage")
- }
sourceSets.androidTest.assets.srcDirs +=
project.rootDir.absolutePath + "/../../golden/compose/material/material"
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt
index bb7e4d1..262d15c 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/OutlinedTextFieldTest.kt
@@ -52,8 +52,10 @@
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performGesture
import androidx.compose.ui.test.performImeAction
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.SoftwareKeyboardController
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
@@ -585,6 +587,7 @@
}
}
+ @OptIn(ExperimentalTextApi::class)
@Test
fun testOutlinedTextField_imeActionAndKeyboardTypePropagatedDownstream() {
val textInputService = mock<TextInputService>()
@@ -609,9 +612,12 @@
rule.runOnIdle {
verify(textInputService, atLeastOnce()).startInput(
value = any(),
- keyboardType = eq(KeyboardType.Email),
- imeAction = eq(ImeAction.Go),
- keyboardOptions = any(),
+ keyboardOptions = eq(
+ KeyboardOptions(
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Go
+ )
+ ),
>
>
)
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
index c45a667..44146de 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
@@ -63,8 +63,10 @@
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performGesture
import androidx.compose.ui.test.performImeAction
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.SoftwareKeyboardController
import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.KeyboardOptions
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
@@ -738,6 +740,7 @@
}
}
+ @OptIn(ExperimentalTextApi::class)
@Test
fun testTextField_imeActionAndKeyboardTypePropagatedDownstream() {
val textInputService = mock<TextInputService>()
@@ -762,9 +765,12 @@
rule.runOnIdle {
verify(textInputService, atLeastOnce()).startInput(
value = any(),
- keyboardType = eq(KeyboardType.Email),
- imeAction = eq(ImeAction.Go),
- keyboardOptions = any(),
+ keyboardOptions = eq(
+ KeyboardOptions(
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Go
+ )
+ ),
>
>
)
diff --git a/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/junit4/TextInputServiceForTests.kt b/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/junit4/TextInputServiceForTests.kt
index bf683e3..4d33f9f 100644
--- a/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/junit4/TextInputServiceForTests.kt
+++ b/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/junit4/TextInputServiceForTests.kt
@@ -21,7 +21,6 @@
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.InputSessionToken
import androidx.compose.ui.text.input.KeyboardOptions
-import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.TextInputService
@@ -43,8 +42,6 @@
override fun startInput(
value: TextFieldValue,
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
@@ -53,8 +50,6 @@
this.>
return super.startInput(
value,
- keyboardType,
- imeAction,
keyboardOptions,
onEditCommand,
onImeActionPerformed
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index 6b140dc..4c8e03a 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -791,17 +791,23 @@
}
@androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public final class KeyboardOptions {
- ctor public KeyboardOptions(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect);
+ ctor public KeyboardOptions(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction);
ctor public KeyboardOptions();
method public boolean component1();
method public androidx.compose.ui.text.input.KeyboardCapitalization component2();
method public boolean component3();
- method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect);
+ method public androidx.compose.ui.text.input.KeyboardType component4();
+ method public androidx.compose.ui.text.input.ImeAction component5();
+ method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction);
method public boolean getAutoCorrect();
method public androidx.compose.ui.text.input.KeyboardCapitalization getCapitalization();
+ method public androidx.compose.ui.text.input.ImeAction getImeAction();
+ method public androidx.compose.ui.text.input.KeyboardType getKeyboardType();
method public boolean getSingleLine();
property public final boolean autoCorrect;
property public final androidx.compose.ui.text.input.KeyboardCapitalization capitalization;
+ property public final androidx.compose.ui.text.input.ImeAction imeAction;
+ property public final androidx.compose.ui.text.input.KeyboardType keyboardType;
property public final boolean singleLine;
field public static final androidx.compose.ui.text.input.KeyboardOptions.Companion Companion;
}
@@ -857,7 +863,7 @@
method public void notifyFocusedRect(androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard();
- method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput();
}
@@ -928,7 +934,7 @@
method public void notifyFocusedRect(int token, androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(int token, androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard(int token);
- method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput(int token);
}
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index 6b140dc..4c8e03a 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -791,17 +791,23 @@
}
@androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public final class KeyboardOptions {
- ctor public KeyboardOptions(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect);
+ ctor public KeyboardOptions(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction);
ctor public KeyboardOptions();
method public boolean component1();
method public androidx.compose.ui.text.input.KeyboardCapitalization component2();
method public boolean component3();
- method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect);
+ method public androidx.compose.ui.text.input.KeyboardType component4();
+ method public androidx.compose.ui.text.input.ImeAction component5();
+ method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction);
method public boolean getAutoCorrect();
method public androidx.compose.ui.text.input.KeyboardCapitalization getCapitalization();
+ method public androidx.compose.ui.text.input.ImeAction getImeAction();
+ method public androidx.compose.ui.text.input.KeyboardType getKeyboardType();
method public boolean getSingleLine();
property public final boolean autoCorrect;
property public final androidx.compose.ui.text.input.KeyboardCapitalization capitalization;
+ property public final androidx.compose.ui.text.input.ImeAction imeAction;
+ property public final androidx.compose.ui.text.input.KeyboardType keyboardType;
property public final boolean singleLine;
field public static final androidx.compose.ui.text.input.KeyboardOptions.Companion Companion;
}
@@ -857,7 +863,7 @@
method public void notifyFocusedRect(androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard();
- method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput();
}
@@ -928,7 +934,7 @@
method public void notifyFocusedRect(int token, androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(int token, androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard(int token);
- method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput(int token);
}
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index 6b140dc..4c8e03a 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -791,17 +791,23 @@
}
@androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public final class KeyboardOptions {
- ctor public KeyboardOptions(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect);
+ ctor public KeyboardOptions(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction);
ctor public KeyboardOptions();
method public boolean component1();
method public androidx.compose.ui.text.input.KeyboardCapitalization component2();
method public boolean component3();
- method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect);
+ method public androidx.compose.ui.text.input.KeyboardType component4();
+ method public androidx.compose.ui.text.input.ImeAction component5();
+ method @androidx.compose.runtime.Immutable @androidx.compose.ui.text.ExperimentalTextApi public androidx.compose.ui.text.input.KeyboardOptions copy(boolean singleLine, androidx.compose.ui.text.input.KeyboardCapitalization capitalization, boolean autoCorrect, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction);
method public boolean getAutoCorrect();
method public androidx.compose.ui.text.input.KeyboardCapitalization getCapitalization();
+ method public androidx.compose.ui.text.input.ImeAction getImeAction();
+ method public androidx.compose.ui.text.input.KeyboardType getKeyboardType();
method public boolean getSingleLine();
property public final boolean autoCorrect;
property public final androidx.compose.ui.text.input.KeyboardCapitalization capitalization;
+ property public final androidx.compose.ui.text.input.ImeAction imeAction;
+ property public final androidx.compose.ui.text.input.KeyboardType keyboardType;
property public final boolean singleLine;
field public static final androidx.compose.ui.text.input.KeyboardOptions.Companion Companion;
}
@@ -857,7 +863,7 @@
method public void notifyFocusedRect(androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard();
- method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public void startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput();
}
@@ -928,7 +934,7 @@
method public void notifyFocusedRect(int token, androidx.compose.ui.geometry.Rect rect);
method public void onStateUpdated(int token, androidx.compose.ui.text.input.TextFieldValue value);
method public void showSoftwareKeyboard(int token);
- method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardType keyboardType, androidx.compose.ui.text.input.ImeAction imeAction, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+ method public int startInput(androidx.compose.ui.text.input.TextFieldValue value, androidx.compose.ui.text.input.KeyboardOptions keyboardOptions, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.compose.ui.text.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.ImeAction,kotlin.Unit> onImeActionPerformed);
method public void stopInput(int token);
}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/KeyboardOptions.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/KeyboardOptions.kt
index 4ff2536..0a44c86 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/KeyboardOptions.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/KeyboardOptions.kt
@@ -33,13 +33,21 @@
* text based [KeyboardType]s such as [KeyboardType.Email], [KeyboardType.Uri]. It will not be
* applied to [KeyboardType]s such as [KeyboardType.Number]. Most of software keyboard
* implementations ignore this value for [KeyboardType]s such as [KeyboardType.Text].
+ * @param keyboardType The keyboard type to be used in this text field. Note that this input type
+ * is honored by IME and shows corresponding keyboard but this is not guaranteed. For example,
+ * some IME may send non-ASCII character even if you set [KeyboardType.Ascii].
+ * @param imeAction The IME action. This IME action is honored by IME and may show specific icons
+ * on the keyboard. For example, search icon may be shown if [ImeAction.Search] is specified.
+ * When [singleLine] is false, the IME might show return key rather than the action requested here.
*/
@ExperimentalTextApi
@Immutable
data class KeyboardOptions(
val singleLine: Boolean = false,
val capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
- val autoCorrect: Boolean = true
+ val autoCorrect: Boolean = true,
+ val keyboardType: KeyboardType = KeyboardType.Text,
+ val imeAction: ImeAction = ImeAction.Unspecified,
) {
companion object {
val Default = KeyboardOptions()
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt
index af755c7..828c2e2 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/TextInputService.kt
@@ -61,16 +61,12 @@
*/
open fun startInput(
value: TextFieldValue,
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
): InputSessionToken {
platformTextInputService.startInput(
value,
- keyboardType,
- imeAction,
keyboardOptions,
onEditCommand,
onImeActionPerformed
@@ -131,8 +127,6 @@
*/
fun startInput(
value: TextFieldValue,
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt
index 48ae334..b52651f 100644
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextInputServiceTest.kt
@@ -19,9 +19,7 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardOptions
-import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.TextInputService
@@ -48,16 +46,12 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
)
val secondToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -74,8 +68,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -93,8 +85,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -103,8 +93,6 @@
// Start another session. The firstToken is now expired.
textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -122,8 +110,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -141,8 +127,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -151,8 +135,6 @@
// Start another session. The firstToken is now expired.
textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -170,8 +152,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -190,8 +170,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -200,8 +178,6 @@
// Start another session. The firstToken is now expired.
textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -220,8 +196,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -240,8 +214,6 @@
val firstToken = textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
@@ -250,8 +222,6 @@
// Start another session. The firstToken is now expired.
textInputService.startInput(
TextFieldValue(),
- KeyboardType.Text,
- ImeAction.NoAction,
KeyboardOptions.Default,
{}, // onEditCommand
{} // onImeActionPerformed
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 408faf1..5d864f1 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2304,7 +2304,8 @@
public final class SelectionContainerKt {
method @androidx.compose.runtime.Composable public static void DisableSelection(kotlin.jvm.functions.Function0<kotlin.Unit> content);
- method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, androidx.compose.ui.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.compose.ui.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method @Deprecated @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, androidx.compose.ui.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.compose.ui.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
}
public final class SelectionHandlesKt {
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index 408faf1..5d864f1 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -2304,7 +2304,8 @@
public final class SelectionContainerKt {
method @androidx.compose.runtime.Composable public static void DisableSelection(kotlin.jvm.functions.Function0<kotlin.Unit> content);
- method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, androidx.compose.ui.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.compose.ui.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method @Deprecated @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, androidx.compose.ui.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.compose.ui.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
}
public final class SelectionHandlesKt {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 80235fd..0bbc3bd 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2381,7 +2381,8 @@
public final class SelectionContainerKt {
method @androidx.compose.runtime.Composable public static void DisableSelection(kotlin.jvm.functions.Function0<kotlin.Unit> content);
- method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, androidx.compose.ui.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.compose.ui.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method @androidx.compose.runtime.Composable public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+ method @Deprecated @androidx.compose.runtime.Composable @androidx.compose.ui.text.InternalTextApi public static void SelectionContainer(optional androidx.compose.ui.Modifier modifier, androidx.compose.ui.selection.Selection? selection, kotlin.jvm.functions.Function1<? super androidx.compose.ui.selection.Selection,kotlin.Unit> onSelectionChange, kotlin.jvm.functions.Function0<kotlin.Unit> children);
}
public final class SelectionHandlesKt {
diff --git a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/SelectionSample.kt b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/SelectionSample.kt
new file mode 100644
index 0000000..2735be2
--- /dev/null
+++ b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/SelectionSample.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.foundation.Text
+import androidx.compose.foundation.layout.Column
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.selection.DisableSelection
+import androidx.compose.ui.selection.SelectionContainer
+
+@Sampled
+@Composable
+fun SelectionSample() {
+ SelectionContainer {
+ Column {
+ Text("Text 1")
+ Text("Text 2")
+ Text("טקסט 3")
+ }
+ }
+}
+
+@Sampled
+@Composable
+fun DisableSelectionSample() {
+ SelectionContainer {
+ Column {
+ Text("Text 1")
+
+ DisableSelection {
+ Text("Text 2")
+ Text("טקסט 3")
+ }
+
+ Text("Text 3")
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawLayerTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawLayerTest.kt
index 42cd2f7..34a1af6 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawLayerTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawLayerTest.kt
@@ -50,13 +50,12 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.test.filters.SdkSuppress
-import androidx.test.filters.SmallTest
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-@SmallTest
+@MediumTest
@RunWith(AndroidJUnit4::class)
class DrawLayerTest {
@Suppress("DEPRECATION")
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt
index 5097dbf..347de95 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.kt
@@ -44,8 +44,6 @@
private var onImeActionPerformed: (ImeAction) -> Unit = {}
private var state = TextFieldValue(text = "", selection = TextRange.Zero)
- private var keyboardType = KeyboardType.Text
- private var imeAction = ImeAction.Unspecified
private var keyboardOptions = KeyboardOptions.Default
private var ic: RecordingInputConnection? = null
private var focusedRect: android.graphics.Rect? = null
@@ -80,7 +78,7 @@
if (!editorHasFocus) {
return null
}
- fillEditorInfo(keyboardType, imeAction, keyboardOptions, outAttrs)
+ fillEditorInfo(keyboardOptions, outAttrs)
return RecordingInputConnection(
initState = state,
@@ -104,8 +102,6 @@
override fun startInput(
value: TextFieldValue,
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
@@ -113,8 +109,6 @@
imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
editorHasFocus = true
state = value
- this.keyboardType = keyboardType
- this.imeAction = imeAction
this.keyboardOptions = keyboardOptions
this.>
this.>
@@ -171,12 +165,10 @@
* Fills necessary info of EditorInfo.
*/
private fun fillEditorInfo(
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
outInfo: EditorInfo
) {
- outInfo.imeOptions = when (imeAction) {
+ outInfo.imeOptions = when (keyboardOptions.imeAction) {
ImeAction.Unspecified -> {
if (keyboardOptions.singleLine) {
// this is the last resort to enable single line
@@ -194,9 +186,11 @@
ImeAction.Search -> EditorInfo.IME_ACTION_SEARCH
ImeAction.Send -> EditorInfo.IME_ACTION_SEND
ImeAction.Done -> EditorInfo.IME_ACTION_DONE
- else -> throw IllegalArgumentException("Unknown ImeAction: $imeAction")
+ else -> throw IllegalArgumentException(
+ "Unknown ImeAction: ${keyboardOptions.imeAction}"
+ )
}
- when (keyboardType) {
+ when (keyboardOptions.keyboardType) {
KeyboardType.Text -> outInfo.inputType = InputType.TYPE_CLASS_TEXT
KeyboardType.Ascii -> {
outInfo.inputType = InputType.TYPE_CLASS_TEXT
@@ -217,7 +211,9 @@
outInfo.inputType =
InputType.TYPE_CLASS_NUMBER or EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD
}
- else -> throw IllegalArgumentException("Unknown KeyboardType: $keyboardType")
+ else -> throw IllegalArgumentException(
+ "Unknown KeyboardType: ${keyboardOptions.keyboardType}"
+ )
}
if (!keyboardOptions.singleLine) {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/selection/SelectionContainer.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/selection/SelectionContainer.kt
index 6ae78f3..6293e8a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/selection/SelectionContainer.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/selection/SelectionContainer.kt
@@ -18,7 +18,10 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Providers
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.gesture.dragGestureFilter
@@ -30,12 +33,48 @@
import androidx.compose.ui.text.InternalTextApi
/**
+ * Enables text selection for it's direct or indirection children.
+ *
+ * @sample androidx.compose.ui.samples.SelectionSample
+ */
+@Suppress("DEPRECATION")
+@OptIn(InternalTextApi::class)
+@Composable
+fun SelectionContainer(modifier: Modifier = Modifier, children: @Composable () -> Unit) {
+ var selection by remember { mutableStateOf<Selection?>(null) }
+ SelectionContainer(
+ modifier = modifier,
+ selection = selection,
+ >
+ selection = it
+ },
+ children = children
+ )
+}
+
+/**
+ * Disables text selection for it's direct or indirection children. To use this, simply add this
+ * to wrap one or more text composables.
+ *
+ * @sample androidx.compose.ui.samples.DisableSelectionSample
+ */
+@Composable
+fun DisableSelection(content: @Composable () -> Unit) {
+ Providers(
+ SelectionRegistrarAmbient provides null,
+ children = content
+ )
+}
+
+/**
* Selection Composable.
*
* The selection composable wraps composables and let them to be selectable. It paints the selection
* area with start and end handles.
*/
@OptIn(InternalTextApi::class)
+@Deprecated("Please use SelectionContainer with no callback")
+@InternalTextApi
@Composable
fun SelectionContainer(
/** A [Modifier] for SelectionContainer. */
@@ -100,19 +139,6 @@
}
}
-/**
- * This is for disabling selection for text when the text is inside a SelectionContainer.
- *
- * To use this, simply add this to wrap one or more text composables.
- */
-@Composable
-fun DisableSelection(content: @Composable () -> Unit) {
- Providers(
- SelectionRegistrarAmbient provides null,
- children = content
- )
-}
-
@Composable
private fun SelectionFloatingToolBar(manager: SelectionManager) {
manager.showSelectionToolbar()
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt
index f8102ed..3f58f6a 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.kt
@@ -23,7 +23,6 @@
import androidx.compose.ui.text.input.EditOperation
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardOptions
-import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.MoveCursorEditOp
import androidx.compose.ui.text.input.PlatformTextInputService
import androidx.compose.ui.text.input.SetComposingTextEditOp
@@ -67,14 +66,12 @@
override fun startInput(
value: TextFieldValue,
- keyboardType: KeyboardType,
- imeAction: ImeAction,
keyboardOptions: KeyboardOptions,
onEditCommand: (List<EditOperation>) -> Unit,
onImeActionPerformed: (ImeAction) -> Unit
) {
val input = CurrentInput(
- value, onEditCommand, onImeActionPerformed, imeAction
+ value, onEditCommand, onImeActionPerformed, keyboardOptions.imeAction
)
currentInput = input
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
index 69e59d7..42da49c 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/input/TextInputServiceAndroidTest.kt
@@ -58,10 +58,11 @@
@Test
fun test_fill_editor_info_text() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Text,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -79,10 +80,11 @@
@Test
fun test_fill_editor_info_ascii() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -101,10 +103,11 @@
@Test
fun test_fill_editor_info_number() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Number,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -122,10 +125,11 @@
@Test
fun test_fill_editor_info_phone() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Phone,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Phone,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -143,10 +147,11 @@
@Test
fun test_fill_editor_info_uri() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Uri,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Uri,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -165,10 +170,11 @@
@Test
fun test_fill_editor_info_email() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Email,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Email,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -187,10 +193,11 @@
@Test
fun test_fill_editor_info_password() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Password,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Password,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -209,10 +216,11 @@
@Test
fun test_fill_editor_info_number_password() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.NumberPassword,
- ImeAction.Unspecified,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.NumberPassword,
+ imeAction = ImeAction.Unspecified
+ ),
>
>
)
@@ -231,10 +239,11 @@
@Test
fun test_fill_editor_info_action_none() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.NoAction,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.NoAction
+ ),
>
>
)
@@ -253,10 +262,11 @@
@Test
fun test_fill_editor_info_action_go() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Go,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Go
+ ),
>
>
)
@@ -275,10 +285,11 @@
@Test
fun test_fill_editor_info_action_next() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Next,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Next
+ ),
>
>
)
@@ -297,10 +308,11 @@
@Test
fun test_fill_editor_info_action_previous() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Previous,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Previous
+ ),
>
>
)
@@ -319,10 +331,11 @@
@Test
fun test_fill_editor_info_action_search() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Search,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Search,
+ ),
>
>
)
@@ -341,10 +354,11 @@
@Test
fun test_fill_editor_info_action_send() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Send,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Send
+ ),
>
>
)
@@ -363,10 +377,11 @@
@Test
fun test_fill_editor_info_action_done() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions.Default,
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -385,10 +400,12 @@
@Test
fun test_fill_editor_info_multi_line() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(singleLine = false),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -403,10 +420,12 @@
@Test
fun test_fill_editor_info_single_line() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(singleLine = true),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -421,10 +440,12 @@
@Test
fun test_fill_editor_info_single_line_changes_ime_from_unspecified_to_done() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Text,
- ImeAction.Unspecified,
- KeyboardOptions(singleLine = true),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ singleLine = true,
+ keyboardType = KeyboardType.Text,
+ imeAction = ImeAction.Unspecified,
+ ),
>
>
)
@@ -439,10 +460,12 @@
@Test
fun test_fill_editor_info_multi_line_not_set_when_input_type_is_not_text() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Number,
- ImeAction.Done,
- KeyboardOptions(singleLine = false),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ singleLine = false,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -457,10 +480,12 @@
@Test
fun test_fill_editor_info_capitalization_none() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(capitalization = KeyboardCapitalization.None),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.None,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -476,10 +501,12 @@
@Test
fun test_fill_editor_info_capitalization_characters() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(capitalization = KeyboardCapitalization.Characters),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Characters,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -495,10 +522,12 @@
@Test
fun test_fill_editor_info_capitalization_words() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(capitalization = KeyboardCapitalization.Words),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Words,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -514,10 +543,12 @@
@Test
fun test_fill_editor_info_capitalization_sentences() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done,
+ ),
>
>
)
@@ -533,10 +564,12 @@
@Test
fun test_fill_editor_info_capitalization_not_added_when_input_type_is_not_text() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Number,
- ImeAction.Done,
- KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ capitalization = KeyboardCapitalization.Sentences,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done,
+ ),
>
>
)
@@ -552,10 +585,12 @@
@Test
fun test_fill_editor_info_auto_correct_on() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(autoCorrect = true),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ autoCorrect = true,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -569,10 +604,12 @@
@Test
fun test_fill_editor_info_auto_correct_off() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Ascii,
- ImeAction.Done,
- KeyboardOptions(autoCorrect = false),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ autoCorrect = false,
+ keyboardType = KeyboardType.Ascii,
+ imeAction = ImeAction.Done
+ ),
>
>
)
@@ -586,10 +623,12 @@
@Test
fun autocorrect_not_added_when_input_type_is_not_text() {
textInputService.startInput(
- TextFieldValue(""),
- KeyboardType.Number,
- ImeAction.Done,
- KeyboardOptions(autoCorrect = true),
+ value = TextFieldValue(""),
+ keyboardOptions = KeyboardOptions(
+ autoCorrect = true,
+ keyboardType = KeyboardType.Number,
+ imeAction = ImeAction.Done
+ ),
>
>
)
diff --git a/navigation/navigation-compose/build.gradle b/navigation/navigation-compose/build.gradle
index dde8efc..3beca1c 100644
--- a/navigation/navigation-compose/build.gradle
+++ b/navigation/navigation-compose/build.gradle
@@ -34,6 +34,7 @@
implementation(KOTLIN_STDLIB)
api project(":compose:runtime:runtime")
+ api project(":compose:runtime:runtime-saved-instance-state")
api project(":compose:ui:ui")
api "androidx.navigation:navigation-runtime-ktx:2.3.1"
diff --git a/test/screenshot/build.gradle b/test/screenshot/build.gradle
index 72f2376..21e4e0a 100644
--- a/test/screenshot/build.gradle
+++ b/test/screenshot/build.gradle
@@ -43,10 +43,4 @@
androidx {
name = "AndroidX Library Screenshot Test"
mavenGroup = LibraryGroups.TESTSCREENSHOT
-}
-
-android {
- defaultConfig {
- testInstrumentationRunnerArgument("thisisignored", "thisisignored --no-isolated-storage")
- }
}
\ No newline at end of file
diff --git a/test/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt b/test/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt
index 36706d1..341e0b0 100644
--- a/test/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt
+++ b/test/screenshot/src/main/java/androidx/test/screenshot/ScreenshotTestRule.kt
@@ -20,6 +20,7 @@
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
+import android.os.Bundle
import androidx.core.os.BuildCompat
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.screenshot.matchers.BitmapMatcher
@@ -82,7 +83,11 @@
/**
* Directory on the device that is used to store the output files.
*/
- val deviceOutputDirectory = File("/sdcard", "androidx_screenshots")
+ val deviceOutputDirectory
+ get() = File(
+ InstrumentationRegistry.getInstrumentation().getContext().externalCacheDir,
+ "androidx_screenshots"
+ )
private val repoRootPathForGoldens = config.repoRootPathForGoldens.trim('/')
private val pathToGoldensInRepo = config.pathToGoldensInRepo.trim('/')
@@ -90,6 +95,10 @@
// This is used in CI to identify the files.
private val resultProtoFileSuffix = "goldResult.textproto"
+ // Magic number for an in-progress status report
+ private val bundleStatusInProgress = 2
+ private val bundleKeyPrefix = "androidx_screenshots_"
+
private lateinit var testIdentifier: String
private lateinit var deviceId: String
@@ -252,20 +261,37 @@
"$pathToGoldensInRepo/${goldenIdentifierResolver(goldenIdentifier)}"
}
+ val report = Bundle()
+
if (status != ScreenshotResultProto.ScreenshotResult.Status.PASSED) {
- resultProto.currentScreenshotFileName =
- actual.writeToDevice(OutputFileType.IMAGE_ACTUAL)
+ actual.writeToDevice(OutputFileType.IMAGE_ACTUAL).also {
+ resultProto.currentScreenshotFileName = it.name
+ report.putString(bundleKeyPrefix + OutputFileType.IMAGE_ACTUAL, it.absolutePath)
+ }
diff?.run {
- resultProto.diffImageFileName = writeToDevice(OutputFileType.IMAGE_DIFF)
+ writeToDevice(OutputFileType.IMAGE_DIFF).also {
+ resultProto.diffImageFileName = it.name
+ report.putString(bundleKeyPrefix + OutputFileType.IMAGE_DIFF, it.absolutePath)
+ }
}
expected?.run {
- resultProto.expectedImageFileName = writeToDevice(OutputFileType.IMAGE_EXPECTED)
+ writeToDevice(OutputFileType.IMAGE_EXPECTED).also {
+ resultProto.expectedImageFileName = it.name
+ report.putString(
+ bundleKeyPrefix + OutputFileType.IMAGE_EXPECTED,
+ it.absolutePath
+ )
+ }
}
}
writeToDevice(OutputFileType.RESULT_PROTO) {
it.write(resultProto.build().toString().toByteArray())
+ }.also {
+ report.putString(bundleKeyPrefix + OutputFileType.RESULT_PROTO, it.absolutePath)
}
+
+ InstrumentationRegistry.getInstrumentation().sendStatus(bundleStatusInProgress, report)
}
internal fun getPathOnDeviceFor(fileType: OutputFileType): File {
@@ -278,32 +304,34 @@
return File(deviceOutputDirectory, fileName)
}
- private fun Bitmap.writeToDevice(fileType: OutputFileType): String {
+ private fun Bitmap.writeToDevice(fileType: OutputFileType): File {
return writeToDevice(fileType) {
compress(Bitmap.CompressFormat.PNG, 0 /*ignored for png*/, it)
}
}
- private fun writeToDevice(fileType: OutputFileType, writeAction: (FileOutputStream) -> Unit):
- String {
- if (!deviceOutputDirectory.exists() && !deviceOutputDirectory.mkdir()) {
- throw IOException("Could not create folder.")
- }
-
- var file = getPathOnDeviceFor(fileType)
- try {
- FileOutputStream(file).use {
- writeAction(it)
- }
- } catch (e: Exception) {
- throw IOException(
- "Could not write file to storage (path: ${file.absolutePath}). " +
- " Stacktrace: " + e.stackTrace
- )
- }
- return file.name
+ private fun writeToDevice(
+ fileType: OutputFileType,
+ writeAction: (FileOutputStream) -> Unit
+ ): File {
+ if (!deviceOutputDirectory.exists() && !deviceOutputDirectory.mkdir()) {
+ throw IOException("Could not create folder.")
}
+ var file = getPathOnDeviceFor(fileType)
+ try {
+ FileOutputStream(file).use {
+ writeAction(it)
+ }
+ } catch (e: Exception) {
+ throw IOException(
+ "Could not write file to storage (path: ${file.absolutePath}). " +
+ " Stacktrace: " + e.stackTrace
+ )
+ }
+ return file
+ }
+
private fun getDeviceModel(): String {
var model = android.os.Build.MODEL.toLowerCase()
arrayOf("phone", "x86", "x64").forEach {