Merge "Update kotlinx.coroutines to version 1.5.0" into androidx-main
diff --git a/buildSrc/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt
index 9afdb1d..7069810 100644
--- a/buildSrc/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/docs/AndroidXDocsPlugin.kt
@@ -559,7 +559,7 @@
}
}
-private const val DACKKA_DEPENDENCY = "com.google.devsite:dackka:0.0.5"
+private const val DACKKA_DEPENDENCY = "com.google.devsite:dackka:0.0.6"
private const val DOCLAVA_DEPENDENCY = "com.android:doclava:1.0.6"
// Allowlist for directories that should be processed by Dackka
diff --git a/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt b/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt
index 1de98bf..02db5e1 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/main/java/androidx/camera/integration/uiwidgets/viewpager/CameraFragment.kt
@@ -73,7 +73,7 @@
Log.d(TAG, "Skip camera setup since the lifecycle is closed")
}
},
- ContextCompat.getMainExecutor(this.context)
+ ContextCompat.getMainExecutor(requireContext())
)
}
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
index 9c67c3f..b5997ab 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
@@ -31,7 +31,6 @@
import androidx.car.app.model.CarIcon;
import androidx.car.app.model.InputCallback;
import androidx.car.app.model.MessageTemplate;
-import androidx.car.app.model.OnInputCompletedListener;
import androidx.car.app.model.ParkedOnlyOnClickListener;
import androidx.car.app.model.Template;
import androidx.car.app.model.signin.InputSignInMethod;
@@ -200,17 +199,20 @@
}
private Template getPasswordSignInTemplate() {
- OnInputCompletedListener listener = text -> {
- // Mocked password validation
- if (!EXPECTED_PASSWORD.equals(text)) {
- mErrorMessage = "Invalid password";
- } else {
- mErrorMessage = "";
- mState = State.SIGNED_IN;
+ InputCallback callback = new InputCallback() {
+ @Override
+ public void onInputSubmitted(@NonNull String text) {
+ // Mocked password validation
+ if (!EXPECTED_PASSWORD.equals(text)) {
+ mErrorMessage = "Invalid password";
+ } else {
+ mErrorMessage = "";
+ mState = State.SIGNED_IN;
+ }
+ invalidate();
}
- invalidate();
};
- InputSignInMethod.Builder builder = new InputSignInMethod.Builder(listener)
+ InputSignInMethod.Builder builder = new InputSignInMethod.Builder(callback)
.setHint("Password")
.setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD);
if (mErrorMessage != null) {
diff --git a/car/app/app/api/current.txt b/car/app/app/api/current.txt
index 73194f8..202be75 100644
--- a/car/app/app/api/current.txt
+++ b/car/app/app/api/current.txt
@@ -246,8 +246,8 @@
package androidx.car.app.hardware.info {
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Accelerometer {
- ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getForces();
+ ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getForces();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarHardwareLocation {
@@ -283,8 +283,8 @@
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Compass {
- ctor public Compass(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getOrientations();
+ ctor public Compass(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getOrientations();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyLevel {
@@ -306,8 +306,8 @@
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyProfile {
- method public androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!> getEvConnectorTypes();
- method public androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!> getFuelTypes();
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getEvConnectorTypes();
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getFuelTypes();
field public static final int EVCONNECTOR_TYPE_CHADEMO = 3; // 0x3
field public static final int EVCONNECTOR_TYPE_COMBO_1 = 4; // 0x4
field public static final int EVCONNECTOR_TYPE_COMBO_2 = 5; // 0x5
@@ -339,13 +339,13 @@
public static final class EnergyProfile.Builder {
ctor public EnergyProfile.Builder();
method public androidx.car.app.hardware.info.EnergyProfile build();
- method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!>);
- method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!>);
+ method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Gyroscope {
- ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getRotations();
+ ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getRotations();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Mileage {
@@ -738,14 +738,6 @@
method public void onClick();
}
- @androidx.car.app.annotations.RequiresCarApi(2) public interface OnInputCompletedDelegate {
- method public void sendInputCompleted(String, androidx.car.app.OnDoneCallback);
- }
-
- @androidx.car.app.annotations.RequiresCarApi(2) public interface OnInputCompletedListener {
- method public void onInputCompleted(String);
- }
-
@androidx.car.app.annotations.CarProtocol public interface OnItemVisibilityChangedDelegate {
method public void sendItemVisibilityChanged(int, int, androidx.car.app.OnDoneCallback);
}
@@ -957,10 +949,9 @@
method public androidx.car.app.model.CarText? getDefaultValue();
method public androidx.car.app.model.CarText? getErrorMessage();
method public androidx.car.app.model.CarText? getHint();
- method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
+ method public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
method public int getInputType();
method public int getKeyboardType();
- method public androidx.car.app.model.OnInputCompletedDelegate getOnInputCompletedDelegate();
method public boolean isShowKeyboardByDefault();
field public static final int INPUT_TYPE_DEFAULT = 1; // 0x1
field public static final int INPUT_TYPE_PASSWORD = 2; // 0x2
@@ -971,8 +962,7 @@
}
public static final class InputSignInMethod.Builder {
- ctor public InputSignInMethod.Builder(androidx.car.app.model.OnInputCompletedListener);
- ctor @androidx.car.app.annotations.RequiresCarApi(2) public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
+ ctor public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
method public androidx.car.app.model.signin.InputSignInMethod build();
method public androidx.car.app.model.signin.InputSignInMethod.Builder setDefaultValue(String);
method public androidx.car.app.model.signin.InputSignInMethod.Builder setErrorMessage(CharSequence);
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index b5cdda3..85629b1 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -249,8 +249,8 @@
package androidx.car.app.hardware.info {
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Accelerometer {
- ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getForces();
+ ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getForces();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarHardwareLocation {
@@ -286,8 +286,8 @@
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Compass {
- ctor public Compass(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getOrientations();
+ ctor public Compass(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getOrientations();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyLevel {
@@ -309,8 +309,8 @@
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyProfile {
- method public androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!> getEvConnectorTypes();
- method public androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!> getFuelTypes();
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getEvConnectorTypes();
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getFuelTypes();
field public static final int EVCONNECTOR_TYPE_CHADEMO = 3; // 0x3
field public static final int EVCONNECTOR_TYPE_COMBO_1 = 4; // 0x4
field public static final int EVCONNECTOR_TYPE_COMBO_2 = 5; // 0x5
@@ -342,13 +342,13 @@
public static final class EnergyProfile.Builder {
ctor public EnergyProfile.Builder();
method public androidx.car.app.hardware.info.EnergyProfile build();
- method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!>);
- method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!>);
+ method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Gyroscope {
- ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getRotations();
+ ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getRotations();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Mileage {
@@ -741,14 +741,6 @@
method public void onClick();
}
- @androidx.car.app.annotations.RequiresCarApi(2) public interface OnInputCompletedDelegate {
- method public void sendInputCompleted(String, androidx.car.app.OnDoneCallback);
- }
-
- @androidx.car.app.annotations.RequiresCarApi(2) public interface OnInputCompletedListener {
- method public void onInputCompleted(String);
- }
-
@androidx.car.app.annotations.CarProtocol public interface OnItemVisibilityChangedDelegate {
method public void sendItemVisibilityChanged(int, int, androidx.car.app.OnDoneCallback);
}
@@ -960,10 +952,9 @@
method public androidx.car.app.model.CarText? getDefaultValue();
method public androidx.car.app.model.CarText? getErrorMessage();
method public androidx.car.app.model.CarText? getHint();
- method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
+ method public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
method public int getInputType();
method public int getKeyboardType();
- method public androidx.car.app.model.OnInputCompletedDelegate getOnInputCompletedDelegate();
method public boolean isShowKeyboardByDefault();
field public static final int INPUT_TYPE_DEFAULT = 1; // 0x1
field public static final int INPUT_TYPE_PASSWORD = 2; // 0x2
@@ -974,8 +965,7 @@
}
public static final class InputSignInMethod.Builder {
- ctor public InputSignInMethod.Builder(androidx.car.app.model.OnInputCompletedListener);
- ctor @androidx.car.app.annotations.RequiresCarApi(2) public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
+ ctor public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
method public androidx.car.app.model.signin.InputSignInMethod build();
method public androidx.car.app.model.signin.InputSignInMethod.Builder setDefaultValue(String);
method public androidx.car.app.model.signin.InputSignInMethod.Builder setErrorMessage(CharSequence);
diff --git a/car/app/app/api/restricted_current.txt b/car/app/app/api/restricted_current.txt
index 73194f8..202be75 100644
--- a/car/app/app/api/restricted_current.txt
+++ b/car/app/app/api/restricted_current.txt
@@ -246,8 +246,8 @@
package androidx.car.app.hardware.info {
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Accelerometer {
- ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getForces();
+ ctor public Accelerometer(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getForces();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarHardwareLocation {
@@ -283,8 +283,8 @@
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Compass {
- ctor public Compass(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getOrientations();
+ ctor public Compass(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getOrientations();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyLevel {
@@ -306,8 +306,8 @@
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyProfile {
- method public androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!> getEvConnectorTypes();
- method public androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!> getFuelTypes();
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getEvConnectorTypes();
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!> getFuelTypes();
field public static final int EVCONNECTOR_TYPE_CHADEMO = 3; // 0x3
field public static final int EVCONNECTOR_TYPE_COMBO_1 = 4; // 0x4
field public static final int EVCONNECTOR_TYPE_COMBO_2 = 5; // 0x5
@@ -339,13 +339,13 @@
public static final class EnergyProfile.Builder {
ctor public EnergyProfile.Builder();
method public androidx.car.app.hardware.info.EnergyProfile build();
- method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!>);
- method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.lang.Integer![]!>);
+ method public androidx.car.app.hardware.info.EnergyProfile.Builder setEvConnectorTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.info.EnergyProfile.Builder setFuelTypes(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Integer!>!>);
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Gyroscope {
- ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.lang.Float![]!>);
- method public androidx.car.app.hardware.common.CarValue<java.lang.Float![]!> getRotations();
+ ctor public Gyroscope(androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getRotations();
}
@androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Mileage {
@@ -738,14 +738,6 @@
method public void onClick();
}
- @androidx.car.app.annotations.RequiresCarApi(2) public interface OnInputCompletedDelegate {
- method public void sendInputCompleted(String, androidx.car.app.OnDoneCallback);
- }
-
- @androidx.car.app.annotations.RequiresCarApi(2) public interface OnInputCompletedListener {
- method public void onInputCompleted(String);
- }
-
@androidx.car.app.annotations.CarProtocol public interface OnItemVisibilityChangedDelegate {
method public void sendItemVisibilityChanged(int, int, androidx.car.app.OnDoneCallback);
}
@@ -957,10 +949,9 @@
method public androidx.car.app.model.CarText? getDefaultValue();
method public androidx.car.app.model.CarText? getErrorMessage();
method public androidx.car.app.model.CarText? getHint();
- method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
+ method public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
method public int getInputType();
method public int getKeyboardType();
- method public androidx.car.app.model.OnInputCompletedDelegate getOnInputCompletedDelegate();
method public boolean isShowKeyboardByDefault();
field public static final int INPUT_TYPE_DEFAULT = 1; // 0x1
field public static final int INPUT_TYPE_PASSWORD = 2; // 0x2
@@ -971,8 +962,7 @@
}
public static final class InputSignInMethod.Builder {
- ctor public InputSignInMethod.Builder(androidx.car.app.model.OnInputCompletedListener);
- ctor @androidx.car.app.annotations.RequiresCarApi(2) public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
+ ctor public InputSignInMethod.Builder(androidx.car.app.model.InputCallback);
method public androidx.car.app.model.signin.InputSignInMethod build();
method public androidx.car.app.model.signin.InputSignInMethod.Builder setDefaultValue(String);
method public androidx.car.app.model.signin.InputSignInMethod.Builder setErrorMessage(CharSequence);
diff --git a/car/app/app/src/main/aidl/androidx/car/app/model/IOnInputCompletedListener.aidl b/car/app/app/src/main/aidl/androidx/car/app/model/IOnInputCompletedListener.aidl
deleted file mode 100644
index 632f921..0000000
--- a/car/app/app/src/main/aidl/androidx/car/app/model/IOnInputCompletedListener.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2021 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.car.app.model;
-
-import androidx.car.app.IOnDoneCallback;
-
-/** @hide */
-oneway interface IOnInputCompletedListener {
- void onInputCompleted(String value, IOnDoneCallback callback) = 1;
-}
diff --git a/car/app/app/src/main/java/androidx/car/app/hardware/common/CarValue.java b/car/app/app/src/main/java/androidx/car/app/hardware/common/CarValue.java
index ede436a..eca9dbc 100644
--- a/car/app/app/src/main/java/androidx/car/app/hardware/common/CarValue.java
+++ b/car/app/app/src/main/java/androidx/car/app/hardware/common/CarValue.java
@@ -26,6 +26,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Objects;
/**
@@ -112,11 +113,11 @@
/** @hide */
@RestrictTo(LIBRARY)
- public static final CarValue<Float[]> UNIMPLEMENTED_FLOAT_ARRAY = unimplemented();
+ public static final CarValue<List<Float>> UNIMPLEMENTED_FLOAT_LIST = unimplemented();
/** @hide */
@RestrictTo(LIBRARY)
- public static final CarValue<Integer[]> UNIMPLEMENTED_INTEGER_ARRAY = unimplemented();
+ public static final CarValue<List<Integer>> UNIMPLEMENTED_INTEGER_LIST = unimplemented();
/**
* Returns a the data value or {@code null} if the status is not successful.
diff --git a/car/app/app/src/main/java/androidx/car/app/hardware/info/Accelerometer.java b/car/app/app/src/main/java/androidx/car/app/hardware/info/Accelerometer.java
index 07294ca..08b562d 100644
--- a/car/app/app/src/main/java/androidx/car/app/hardware/info/Accelerometer.java
+++ b/car/app/app/src/main/java/androidx/car/app/hardware/info/Accelerometer.java
@@ -24,6 +24,7 @@
import androidx.car.app.annotations.RequiresCarApi;
import androidx.car.app.hardware.common.CarValue;
+import java.util.List;
import java.util.Objects;
/** Information about car specific accelerometers available from the car hardware. */
@@ -33,7 +34,7 @@
@Keep
@NonNull
- private final CarValue<Float[]> mForces;
+ private final CarValue<List<Float>> mForces;
/**
* Returns the raw accelerometer force data from the car sensor.
@@ -41,7 +42,7 @@
* <p>Follows the same format as {@link android.hardware.SensorEvent#values}.
*/
@NonNull
- public CarValue<Float[]> getForces() {
+ public CarValue<List<Float>> getForces() {
return mForces;
}
@@ -74,12 +75,12 @@
*
* @throws NullPointerException if {@code forces} is {@code null}
*/
- public Accelerometer(@NonNull CarValue<Float[]> forces) {
+ public Accelerometer(@NonNull CarValue<List<Float>> forces) {
mForces = requireNonNull(forces);
}
/** Constructs an empty instance, used by serialization code. */
private Accelerometer() {
- mForces = CarValue.UNIMPLEMENTED_FLOAT_ARRAY;
+ mForces = CarValue.UNIMPLEMENTED_FLOAT_LIST;
}
}
diff --git a/car/app/app/src/main/java/androidx/car/app/hardware/info/Compass.java b/car/app/app/src/main/java/androidx/car/app/hardware/info/Compass.java
index 4b7ea45..2142740 100644
--- a/car/app/app/src/main/java/androidx/car/app/hardware/info/Compass.java
+++ b/car/app/app/src/main/java/androidx/car/app/hardware/info/Compass.java
@@ -24,6 +24,7 @@
import androidx.car.app.annotations.RequiresCarApi;
import androidx.car.app.hardware.common.CarValue;
+import java.util.List;
import java.util.Objects;
/** Information about car specific compass available from the car hardware. */
@@ -33,7 +34,7 @@
@Keep
@NonNull
- private final CarValue<Float[]> mOrientations;
+ private final CarValue<List<Float>> mOrientations;
/**
* Returns the raw compass data from the car sensor.
@@ -41,8 +42,8 @@
* <p>Follows the same format as {@link android.hardware.SensorEvent#values}.
*/
@NonNull
- public CarValue<Float[]> getOrientations() {
- return requireNonNull(mOrientations);
+ public CarValue<List<Float>> getOrientations() {
+ return mOrientations;
}
@Override
@@ -74,12 +75,12 @@
*
* @throws NullPointerException if {@code orientations} is {@code null}
*/
- public Compass(@NonNull CarValue<Float[]> orientations) {
+ public Compass(@NonNull CarValue<List<Float>> orientations) {
mOrientations = requireNonNull(orientations);
}
/** Constructs an empty instance, used by serialization code. */
private Compass() {
- mOrientations = CarValue.UNIMPLEMENTED_FLOAT_ARRAY;
+ mOrientations = CarValue.UNIMPLEMENTED_FLOAT_LIST;
}
}
diff --git a/car/app/app/src/main/java/androidx/car/app/hardware/info/EnergyProfile.java b/car/app/app/src/main/java/androidx/car/app/hardware/info/EnergyProfile.java
index 7f7bc31..948800f 100644
--- a/car/app/app/src/main/java/androidx/car/app/hardware/info/EnergyProfile.java
+++ b/car/app/app/src/main/java/androidx/car/app/hardware/info/EnergyProfile.java
@@ -30,6 +30,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Objects;
/** Information about car hardware fuel profile such as fuel types and connector ports. */
@@ -168,11 +169,11 @@
@Keep
@NonNull
- private final CarValue<Integer[]> mEvConnectorTypes;
+ private final CarValue<List<Integer>> mEvConnectorTypes;
@Keep
@NonNull
- private final CarValue<Integer[]> mFuelTypes;
+ private final CarValue<List<Integer>> mFuelTypes;
/**
* Returns an array of the available EV connectors.
@@ -182,7 +183,7 @@
* is known but not in the current list {@link #EVCONNECTOR_TYPE_UNKNOWN} will be returned.
*/
@NonNull
- public CarValue<Integer[]> getEvConnectorTypes() {
+ public CarValue<List<Integer>> getEvConnectorTypes() {
return requireNonNull(mEvConnectorTypes);
}
@@ -194,7 +195,7 @@
* {@link #EVCONNECTOR_TYPE_UNKNOWN} will be returned.
*/
@NonNull
- public CarValue<Integer[]> getFuelTypes() {
+ public CarValue<List<Integer>> getFuelTypes() {
return requireNonNull(mFuelTypes);
}
@@ -230,14 +231,14 @@
/** Constructs an empty instance, used by serialization code. */
private EnergyProfile() {
- mEvConnectorTypes = CarValue.UNIMPLEMENTED_INTEGER_ARRAY;
- mFuelTypes = CarValue.UNIMPLEMENTED_INTEGER_ARRAY;
+ mEvConnectorTypes = CarValue.UNIMPLEMENTED_INTEGER_LIST;
+ mFuelTypes = CarValue.UNIMPLEMENTED_INTEGER_LIST;
}
/** A builder of {@link EnergyProfile}. */
public static final class Builder {
- CarValue<Integer[]> mEvConnectorTypes = CarValue.UNIMPLEMENTED_INTEGER_ARRAY;
- CarValue<Integer[]> mFuelTypes = CarValue.UNIMPLEMENTED_INTEGER_ARRAY;
+ CarValue<List<Integer>> mEvConnectorTypes = CarValue.UNIMPLEMENTED_INTEGER_LIST;
+ CarValue<List<Integer>> mFuelTypes = CarValue.UNIMPLEMENTED_INTEGER_LIST;
/**
* Sets the cars EV connector types.
@@ -245,7 +246,7 @@
* @throws NullPointerException if {@code evConnectorTypes} is {@code null}
*/
@NonNull
- public Builder setEvConnectorTypes(@NonNull CarValue<Integer[]> evConnectorTypes) {
+ public Builder setEvConnectorTypes(@NonNull CarValue<List<Integer>> evConnectorTypes) {
mEvConnectorTypes = requireNonNull(evConnectorTypes);
return this;
}
@@ -256,7 +257,7 @@
* @throws NullPointerException if {@code fuelTypes} is {@code null}
*/
@NonNull
- public Builder setFuelTypes(@NonNull CarValue<Integer[]> fuelTypes) {
+ public Builder setFuelTypes(@NonNull CarValue<List<Integer>> fuelTypes) {
mFuelTypes = requireNonNull(fuelTypes);
return this;
}
diff --git a/car/app/app/src/main/java/androidx/car/app/hardware/info/Gyroscope.java b/car/app/app/src/main/java/androidx/car/app/hardware/info/Gyroscope.java
index 4799961..e5a8fa5 100644
--- a/car/app/app/src/main/java/androidx/car/app/hardware/info/Gyroscope.java
+++ b/car/app/app/src/main/java/androidx/car/app/hardware/info/Gyroscope.java
@@ -24,6 +24,7 @@
import androidx.car.app.annotations.RequiresCarApi;
import androidx.car.app.hardware.common.CarValue;
+import java.util.List;
import java.util.Objects;
/** Information about car specific gyroscopes available from the car hardware. */
@@ -32,12 +33,12 @@
public final class Gyroscope {
@Keep
@NonNull
- private final CarValue<Float[]> mRotations;
+ private final CarValue<List<Float>> mRotations;
/** Returns the raw gyroscope data from the car sensor. */
@NonNull
- public CarValue<Float[]> getRotations() {
- return requireNonNull(mRotations);
+ public CarValue<List<Float>> getRotations() {
+ return mRotations;
}
@Override
@@ -69,12 +70,12 @@
*
* @throws NullPointerException if {@code rotations} is {@code null}
*/
- public Gyroscope(@NonNull CarValue<Float[]> rotations) {
+ public Gyroscope(@NonNull CarValue<List<Float>> rotations) {
mRotations = requireNonNull(rotations);
}
/** Constructs an empty instance, used by serialization code. */
private Gyroscope() {
- mRotations = CarValue.UNIMPLEMENTED_FLOAT_ARRAY;
+ mRotations = CarValue.UNIMPLEMENTED_FLOAT_LIST;
}
}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedDelegate.java b/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedDelegate.java
deleted file mode 100644
index 26253de..0000000
--- a/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedDelegate.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2021 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.car.app.model;
-
-import android.annotation.SuppressLint;
-
-import androidx.annotation.NonNull;
-import androidx.car.app.OnDoneCallback;
-import androidx.car.app.annotations.RequiresCarApi;
-
-/**
- * A host-side delegate for sending {@link OnInputCompletedListener} events to the car app.
- */
-@RequiresCarApi(2)
-public interface OnInputCompletedDelegate {
- /**
- * Notifies that user input has completed.
- *
- * @param value the text entered
- * @param callback the {@link OnDoneCallback} to trigger when the client finishes handling
- * the event
- */
- // This mirrors the AIDL class and is not supposed to support an executor as an input.
- @SuppressLint("ExecutorRegistration")
- void sendInputCompleted(@NonNull String value, @NonNull OnDoneCallback callback);
-}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedDelegateImpl.java b/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedDelegateImpl.java
deleted file mode 100644
index 3ac951db..0000000
--- a/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedDelegateImpl.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2021 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.car.app.model;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.SuppressLint;
-import android.os.RemoteException;
-
-import androidx.annotation.Keep;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.car.app.IOnDoneCallback;
-import androidx.car.app.OnDoneCallback;
-import androidx.car.app.utils.RemoteUtils;
-
-/**
- * Implementation class for {@link OnInputCompletedDelegate} to allow IPC for text-input-related
- * events.
- *
- * @hide
- */
-@RestrictTo(LIBRARY)
-public class OnInputCompletedDelegateImpl implements OnInputCompletedDelegate {
-
- @Keep
- @Nullable
- private final IOnInputCompletedListener mListener;
-
- @Override
- public void sendInputCompleted(@NonNull String text, @NonNull OnDoneCallback callback) {
- try {
- requireNonNull(mListener).onInputCompleted(text,
- RemoteUtils.createOnDoneCallbackStub(callback));
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Creates an instance of {@link OnInputCompletedDelegateImpl}. */
- // This mirrors the AIDL class and is not supposed to support an executor as an input.
- @SuppressLint("ExecutorRegistration")
- @NonNull
- public static OnInputCompletedDelegate create(@NonNull OnInputCompletedListener listener) {
- return new OnInputCompletedDelegateImpl(requireNonNull(listener));
- }
-
- private OnInputCompletedDelegateImpl(@NonNull OnInputCompletedListener listener) {
- mListener = new OnInputCompletedStub(listener);
- }
-
- /** For serialization. */
- private OnInputCompletedDelegateImpl() {
- mListener = null;
- }
-
- @Keep // We need to keep these stub for Bundler serialization logic.
- private static class OnInputCompletedStub extends IOnInputCompletedListener.Stub {
- private final OnInputCompletedListener mListener;
-
- OnInputCompletedStub(OnInputCompletedListener listener) {
- mListener = listener;
- }
-
- @Override
- public void onInputCompleted(String value, IOnDoneCallback callback) {
- RemoteUtils.dispatchCallFromHost(callback, "onInputCompleted",
- () -> {
- mListener.onInputCompleted(value);
- return null;
-
- });
- }
- }
-}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedListener.java b/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedListener.java
deleted file mode 100644
index 058d711..0000000
--- a/car/app/app/src/main/java/androidx/car/app/model/OnInputCompletedListener.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2021 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.car.app.model;
-
-import androidx.annotation.NonNull;
-import androidx.car.app.annotations.RequiresCarApi;
-
-/** A listener for handling text input completion event. */
-@RequiresCarApi(2)
-public interface OnInputCompletedListener {
- /**
- * Notifies when the user finished entering text in an input box.
- *
- * <p>This event is sent when the user finishes typing in the keyboard and pressed enter.
- * If the user simply stops typing and closes the keyboard, this event will not be sent.
- *
- * @param text the text that was entered, or an empty string if no text was typed.
- */
- void onInputCompleted(@NonNull String text);
-}
diff --git a/car/app/app/src/main/java/androidx/car/app/model/signin/InputSignInMethod.java b/car/app/app/src/main/java/androidx/car/app/model/signin/InputSignInMethod.java
index 7cf4e7f..a8f4b1bb 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/signin/InputSignInMethod.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/signin/InputSignInMethod.java
@@ -33,9 +33,6 @@
import androidx.car.app.model.InputCallback;
import androidx.car.app.model.InputCallbackDelegate;
import androidx.car.app.model.InputCallbackDelegateImpl;
-import androidx.car.app.model.OnInputCompletedDelegate;
-import androidx.car.app.model.OnInputCompletedDelegateImpl;
-import androidx.car.app.model.OnInputCompletedListener;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -126,9 +123,6 @@
@Keep
@KeyboardType
private final int mKeyboardType;
- @Keep
- @Nullable
- private final OnInputCompletedDelegate mOnInputCompletedDelegate;
@Nullable
private final InputCallbackDelegate mInputCallbackDelegate;
@Keep
@@ -189,21 +183,10 @@
}
/**
- * Returns the {@link OnInputCompletedDelegate} for input callbacks.
- *
- * @see Builder#Builder(OnInputCompletedListener)
- */
- @NonNull
- public OnInputCompletedDelegate getOnInputCompletedDelegate() {
- return requireNonNull(mOnInputCompletedDelegate);
- }
-
- /**
* Returns the {@link InputCallbackDelegate} for input callbacks.
*
* @see Builder#Builder(InputCallback)
*/
- @RequiresCarApi(2)
@NonNull
public InputCallbackDelegate getInputCallbackDelegate() {
return requireNonNull(mInputCallbackDelegate);
@@ -255,7 +238,6 @@
mInputType = builder.mInputType;
mErrorMessage = builder.mErrorMessage;
mKeyboardType = builder.mKeyboardType;
- mOnInputCompletedDelegate = builder.mOnInputCompletedDelegate;
mInputCallbackDelegate = builder.mInputCallbackDelegate;
mShowKeyboardByDefault = builder.mShowKeyboardByDefault;
}
@@ -267,14 +249,12 @@
mInputType = INPUT_TYPE_DEFAULT;
mErrorMessage = null;
mKeyboardType = KEYBOARD_DEFAULT;
- mOnInputCompletedDelegate = null;
mInputCallbackDelegate = null;
mShowKeyboardByDefault = false;
}
/** A builder of {@link InputSignInMethod}. */
public static final class Builder {
- @Nullable final OnInputCompletedDelegate mOnInputCompletedDelegate;
@Nullable final InputCallbackDelegate mInputCallbackDelegate;
@Nullable
CarText mHint;
@@ -399,29 +379,11 @@
* <p>Note that the listener relates to UI events and will be executed on the main thread
* using {@link Looper#getMainLooper()}.
*
- * @param listener the {@link OnInputCompletedListener} to be notified of input events
- * @throws NullPointerException if {@code listener} is {@code null}
- */
- @SuppressLint("ExecutorRegistration")
- public Builder(@NonNull OnInputCompletedListener listener) {
- mInputCallbackDelegate = null;
- mOnInputCompletedDelegate = OnInputCompletedDelegateImpl.create(
- requireNonNull(listener));
- }
-
- /**
- * Returns an {@link InputSignInMethod.Builder} instance.
- *
- * <p>Note that the listener relates to UI events and will be executed on the main thread
- * using {@link Looper#getMainLooper()}.
- *
* @param listener the {@link InputCallbackDelegate} to be notified of input events
* @throws NullPointerException if {@code listener} is {@code null}
*/
- @RequiresCarApi(2)
@SuppressLint("ExecutorRegistration")
public Builder(@NonNull InputCallback listener) {
- mOnInputCompletedDelegate = null;
mInputCallbackDelegate = InputCallbackDelegateImpl.create(
requireNonNull(listener));
}
diff --git a/car/app/app/src/test/java/androidx/car/app/model/signin/InputSignInMethodTest.java b/car/app/app/src/test/java/androidx/car/app/model/signin/InputSignInMethodTest.java
index dc23b8b..70149e2 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/signin/InputSignInMethodTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/signin/InputSignInMethodTest.java
@@ -29,8 +29,6 @@
import androidx.car.app.OnDoneCallback;
import androidx.car.app.model.InputCallback;
import androidx.car.app.model.InputCallbackDelegate;
-import androidx.car.app.model.OnInputCompletedDelegate;
-import androidx.car.app.model.OnInputCompletedListener;
import org.junit.Rule;
import org.junit.Test;
@@ -49,26 +47,17 @@
public final MockitoRule mockito = MockitoJUnit.rule();
@Mock
- OnInputCompletedListener mListener;
- @Mock
InputCallback mCallback;
@Test
public void create_defaultValues() {
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener).build();
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback).build();
assertThat(signIn.getInputType()).isEqualTo(INPUT_TYPE_DEFAULT);
assertThat(signIn.getKeyboardType()).isEqualTo(KEYBOARD_DEFAULT);
assertThat(signIn.getHint()).isNull();
assertThat(signIn.getErrorMessage()).isNull();
assertThat(signIn.isShowKeyboardByDefault()).isFalse();
-
- OnInputCompletedDelegate delegate = signIn.getOnInputCompletedDelegate();
- OnDoneCallback onDoneCallback = mock(OnDoneCallback.class);
- delegate.sendInputCompleted("ABC", onDoneCallback);
-
- verify(mListener).onInputCompleted("ABC");
- verify(onDoneCallback).onSuccess(null);
}
@Test
@@ -97,7 +86,7 @@
@Test
public void create_withInputType() {
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setInputType(INPUT_TYPE_PASSWORD)
.build();
@@ -106,7 +95,7 @@
@Test
public void create_withKeyboardType() {
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setKeyboardType(KEYBOARD_EMAIL)
.build();
@@ -115,7 +104,7 @@
@Test
public void create_wtihPrompt() {
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setHint("Signin")
.build();
@@ -124,7 +113,7 @@
@Test
public void create_withMessage() {
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setErrorMessage("error")
.build();
@@ -133,7 +122,7 @@
@Test
public void create_showKeyboard() {
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setShowKeyboardByDefault(true)
.build();
@@ -147,7 +136,7 @@
String message = "error";
String instructions = "sign";
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint(instructions)
@@ -156,7 +145,7 @@
.build();
assertThat(signIn)
- .isEqualTo(new InputSignInMethod.Builder(mListener)
+ .isEqualTo(new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint(instructions)
@@ -171,7 +160,7 @@
String message = "error";
String instructions = "sign";
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setInputType(INPUT_TYPE_PASSWORD)
.setKeyboardType(keyboardType)
.setHint(instructions)
@@ -180,7 +169,7 @@
.build();
assertThat(signIn)
- .isNotEqualTo(new InputSignInMethod.Builder(mListener)
+ .isNotEqualTo(new InputSignInMethod.Builder(mCallback)
.setInputType(INPUT_TYPE_DEFAULT)
.setKeyboardType(keyboardType)
.setHint(instructions)
@@ -195,7 +184,7 @@
String message = "error";
String instructions = "sign";
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(KEYBOARD_EMAIL)
.setHint(instructions)
@@ -204,7 +193,7 @@
.build();
assertThat(signIn)
- .isNotEqualTo(new InputSignInMethod.Builder(mListener)
+ .isNotEqualTo(new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(KEYBOARD_DEFAULT)
.setHint(instructions)
@@ -219,7 +208,7 @@
int keyboardType = KEYBOARD_EMAIL;
String message = "error";
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint("signin")
@@ -228,7 +217,7 @@
.build();
assertThat(signIn)
- .isNotEqualTo(new InputSignInMethod.Builder(mListener)
+ .isNotEqualTo(new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint("sign2")
@@ -243,7 +232,7 @@
int keyboardType = KEYBOARD_EMAIL;
String instructions = "sign";
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint(instructions)
@@ -252,7 +241,7 @@
.build();
assertThat(signIn)
- .isNotEqualTo(new InputSignInMethod.Builder(mListener)
+ .isNotEqualTo(new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint(instructions)
@@ -268,7 +257,7 @@
String message = "error";
String instructions = "sign";
- InputSignInMethod signIn = new InputSignInMethod.Builder(mListener)
+ InputSignInMethod signIn = new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint(instructions)
@@ -277,7 +266,7 @@
.build();
assertThat(signIn)
- .isNotEqualTo(new InputSignInMethod.Builder(mListener)
+ .isNotEqualTo(new InputSignInMethod.Builder(mCallback)
.setInputType(inputType)
.setKeyboardType(keyboardType)
.setHint(instructions)
diff --git a/compose/benchmark-utils/lint-baseline.xml b/compose/benchmark-utils/lint-baseline.xml
deleted file mode 100644
index 42a176b..0000000
--- a/compose/benchmark-utils/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.0.0-alpha15" type="baseline" client="cli" name="Lint" variant="all" version="7.0.0-alpha15">
-
-</issues>
diff --git a/compose/desktop/desktop/lint-baseline.xml b/compose/desktop/desktop/lint-baseline.xml
deleted file mode 100644
index 297ae16..0000000
--- a/compose/desktop/desktop/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.2.0-beta02" client="gradle" version="4.2.0-beta02">
-
-</issues>
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt
index 625c3aa..e38a03a 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyColumnTest.kt
@@ -34,6 +34,7 @@
import androidx.compose.foundation.layout.requiredSizeIn
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.BasicText
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -41,7 +42,6 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.testutils.WithTouchSlop
import androidx.compose.testutils.assertIsEqualTo
@@ -89,9 +89,7 @@
import com.google.common.truth.IntegerSubject
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.Test
@@ -1542,15 +1540,12 @@
@Test
fun animateScrollToItemDoesNotScrollPastItem() {
lateinit var state: LazyListState
- lateinit var scope: CoroutineScope
var target = 0
var reverse = false
rule.setContent {
val listState = rememberLazyListState()
- val effectScope = rememberCoroutineScope()
SideEffect {
state = listState
- scope = effectScope
}
LazyColumn(Modifier.fillMaxSize(), listState) {
items(2500) { _ ->
@@ -1568,24 +1563,61 @@
// Try a bunch of different targets with varying spacing
listOf(500, 800, 1500, 1600, 1800).forEach {
target = it
- scope.launch {
- state.animateScrollToItem(target)
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ state.animateScrollToItem(target)
+ }
}
- rule.waitForIdle()
- assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ assertThat(state.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
}
reverse = true
listOf(1600, 1500, 800, 500, 0).forEach {
target = it
- scope.launch {
- state.animateScrollToItem(target)
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ state.animateScrollToItem(target)
+ }
}
- rule.waitForIdle()
- assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ assertThat(state.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
+ }
+ }
+
+ @Test
+ fun animateScrollToTheLastItemWhenItemsAreLargerThenTheScreen() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ LazyColumn(Modifier.width(150.dp).height(100.dp), state) {
+ items(20) {
+ Box(Modifier.size(150.dp))
+ }
+ }
+ }
+
+ // Try a bunch of different start indexes
+ listOf(0, 5, 12).forEach {
+ val startIndex = it
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ state.scrollToItem(startIndex)
+ state.animateScrollToItem(19)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(19)
+ assertThat(state.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
}
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListLayoutInfoTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListLayoutInfoTest.kt
index b24e18c..d081014 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListLayoutInfoTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListLayoutInfoTest.kt
@@ -247,11 +247,15 @@
@Test
fun viewportOffsetsAreCorrectWithContentPadding() {
val sizePx = 45
- val topPaddingPx = 10
- val bottomPaddingPx = 15
+ val startPaddingPx = 10
+ val endPaddingPx = 15
val sizeDp = with(rule.density) { sizePx.toDp() }
- val topPaddingDp = with(rule.density) { topPaddingPx.toDp() }
- val bottomPaddingDp = with(rule.density) { bottomPaddingPx.toDp() }
+ val topPaddingDp = with(rule.density) {
+ if (!reverseLayout) startPaddingPx.toDp() else endPaddingPx.toDp()
+ }
+ val bottomPaddingDp = with(rule.density) {
+ if (!reverseLayout) endPaddingPx.toDp() else startPaddingPx.toDp()
+ }
lateinit var state: LazyListState
rule.setContent {
LazyColumn(
@@ -267,8 +271,8 @@
}
rule.runOnIdle {
- assertThat(state.layoutInfo.viewportStartOffset).isEqualTo(-topPaddingPx)
- assertThat(state.layoutInfo.viewportEndOffset).isEqualTo(sizePx - topPaddingPx)
+ assertThat(state.layoutInfo.viewportStartOffset).isEqualTo(-startPaddingPx)
+ assertThat(state.layoutInfo.viewportEndOffset).isEqualTo(sizePx - startPaddingPx)
}
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListsContentPaddingTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListsContentPaddingTest.kt
index 74bf477..9be61a2 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListsContentPaddingTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyListsContentPaddingTest.kt
@@ -28,6 +28,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertLeftPositionInRootIsEqualTo
import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
import androidx.compose.ui.test.assertWidthIsEqualTo
@@ -360,6 +361,42 @@
}
@Test
+ fun column_contentPaddingAndReverseLayout() {
+ val topPadding = itemSize * 2
+ val bottomPadding = itemSize / 2
+ val listSize = itemSize * 3
+ lateinit var state: LazyListState
+ rule.setContentWithTestViewConfiguration {
+ LazyColumn(
+ reverseLayout = true,
+ state = rememberLazyListState().also { state = it },
+ modifier = Modifier.requiredSize(listSize),
+ contentPadding = PaddingValues(top = topPadding, bottom = bottomPadding),
+ ) {
+ items(3) { index ->
+ Box(Modifier.requiredSize(itemSize).testTag("$index"))
+ }
+ }
+ }
+
+ rule.onNodeWithTag("0")
+ .assertTopPositionInRootIsEqualTo(listSize - bottomPadding - itemSize)
+ rule.onNodeWithTag("1")
+ .assertTopPositionInRootIsEqualTo(listSize - bottomPadding - itemSize * 2)
+ // Partially visible.
+ rule.onNodeWithTag("2")
+ .assertTopPositionInRootIsEqualTo(-itemSize / 2)
+
+ // Scroll to the top.
+ state.scrollBy(itemSize * 2.5f)
+
+ rule.onNodeWithTag("2").assertTopPositionInRootIsEqualTo(topPadding)
+ // Shouldn't be visible
+ rule.onNodeWithTag("1").assertIsNotDisplayed()
+ rule.onNodeWithTag("0").assertIsNotDisplayed()
+ }
+
+ @Test
fun row_contentPaddingIsApplied() {
lateinit var state: LazyListState
val containerSize = itemSize * 2
@@ -655,6 +692,42 @@
.assertHeightIsEqualTo(12.dp)
}
+ @Test
+ fun row_contentPaddingAndReverseLayout() {
+ val startPadding = itemSize * 2
+ val endPadding = itemSize / 2
+ val listSize = itemSize * 3
+ lateinit var state: LazyListState
+ rule.setContentWithTestViewConfiguration {
+ LazyRow(
+ reverseLayout = true,
+ state = rememberLazyListState().also { state = it },
+ modifier = Modifier.requiredSize(listSize),
+ contentPadding = PaddingValues(start = startPadding, end = endPadding),
+ ) {
+ items(3) { index ->
+ Box(Modifier.requiredSize(itemSize).testTag("$index"))
+ }
+ }
+ }
+
+ rule.onNodeWithTag("0")
+ .assertLeftPositionInRootIsEqualTo(listSize - endPadding - itemSize)
+ rule.onNodeWithTag("1")
+ .assertLeftPositionInRootIsEqualTo(listSize - endPadding - itemSize * 2)
+ // Partially visible.
+ rule.onNodeWithTag("2")
+ .assertLeftPositionInRootIsEqualTo(-itemSize / 2)
+
+ // Scroll to the top.
+ state.scrollBy(itemSize * 2.5f)
+
+ rule.onNodeWithTag("2").assertLeftPositionInRootIsEqualTo(startPadding)
+ // Shouldn't be visible
+ rule.onNodeWithTag("1").assertIsNotDisplayed()
+ rule.onNodeWithTag("0").assertIsNotDisplayed()
+ }
+
private fun LazyListState.scrollBy(offset: Dp) {
runBlocking(Dispatchers.Main + AutoTestFrameClock()) {
animateScrollBy(with(rule.density) { offset.roundToPx().toFloat() }, snap())
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
index c1a3382..fd60d67 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyRowTest.kt
@@ -26,6 +26,7 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredSize
@@ -38,7 +39,6 @@
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.testutils.assertIsEqualTo
import androidx.compose.testutils.assertShape
@@ -76,9 +76,7 @@
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.Test
@@ -1238,15 +1236,12 @@
@Test
fun animateScrollToItemDoesNotScrollPastItem() {
lateinit var state: LazyListState
- lateinit var scope: CoroutineScope
var target = 0
var reverse = false
rule.setContent {
val listState = rememberLazyListState()
- val effectScope = rememberCoroutineScope()
SideEffect {
state = listState
- scope = effectScope
}
LazyRow(Modifier.fillMaxSize(), listState) {
items(2500) { _ ->
@@ -1264,24 +1259,61 @@
// Try a bunch of different targets with varying spacing
listOf(500, 800, 1500, 1600, 1800).forEach {
target = it
- scope.launch {
- state.animateScrollToItem(target)
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ state.animateScrollToItem(target)
+ }
}
- rule.waitForIdle()
- assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ assertThat(state.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
}
reverse = true
listOf(1600, 1500, 800, 500, 0).forEach {
target = it
- scope.launch {
- state.animateScrollToItem(target)
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ state.animateScrollToItem(target)
+ }
}
- rule.waitForIdle()
- assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(target)
+ assertThat(state.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
+ }
+ }
+
+ @Test
+ fun animateScrollToTheLastItemWhenItemsAreLargerThenTheScreen() {
+ lateinit var state: LazyListState
+ rule.setContent {
+ state = rememberLazyListState()
+ LazyRow(Modifier.height(150.dp).width(100.dp), state) {
+ items(20) {
+ Box(Modifier.size(150.dp))
+ }
+ }
+ }
+
+ // Try a bunch of different start indexes
+ listOf(0, 5, 12).forEach {
+ val startIndex = it
+ rule.runOnIdle {
+ runBlocking(AutoTestFrameClock()) {
+ state.scrollToItem(startIndex)
+ state.animateScrollToItem(19)
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(state.firstVisibleItemIndex).isEqualTo(19)
+ assertThat(state.firstVisibleItemScrollOffset).isEqualTo(0)
+ }
}
}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/LazyListPrefetcher.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/LazyListPrefetcher.android.kt
index 0b4c29c..ab9e342 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/LazyListPrefetcher.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/lazy/LazyListPrefetcher.android.kt
@@ -295,10 +295,10 @@
if (premeasuringIsNeeded && index != -1) {
val itemProvider = stateOfItemsProvider.value
if (index < itemProvider.itemsCount) {
- val composedViaRegularFlow = result.visibleItemsInfo.fastAny {
- it.index == index
- }
- if (composedViaRegularFlow) {
+ val isVisibleAlready = result.visibleItemsInfo.fastAny { it.index == index }
+ val composedButNotVisible = result.composedButNotVisibleItems != null &&
+ result.composedButNotVisibleItems.fastAny { it.index == index }
+ if (isVisibleAlready || composedButNotVisible) {
premeasuringIsNeeded = false
} else {
val key = itemProvider.getKey(index)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
index 24a46fbaa..1b86b93 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyList.kt
@@ -153,8 +153,8 @@
itemsCount = itemsCount,
itemProvider = itemProvider,
mainAxisMaxSize = mainAxisMaxSize,
- startContentPadding = startContentPadding,
- endContentPadding = endContentPadding,
+ startContentPadding = if (reverseLayout) endContentPadding else startContentPadding,
+ endContentPadding = if (reverseLayout) startContentPadding else endContentPadding,
firstVisibleItemIndex = state.firstVisibleItemIndexNonObservable,
firstVisibleItemScrollOffset = state.firstVisibleItemScrollOffsetNonObservable,
scrollToBeConsumed = state.scrollToBeConsumed,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt
index dbc8974..6eb219c 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasure.kt
@@ -58,6 +58,7 @@
firstVisibleItemScrollOffset = 0,
canScrollForward = false,
consumedScroll = 0f,
+ composedButNotVisibleItems = null,
layoutWidth = constraints.minWidth,
layoutHeight = constraints.minHeight,
placementBlock = {},
@@ -256,6 +257,7 @@
firstVisibleItemScrollOffset = currentFirstItemScrollOffset,
canScrollForward = mainAxisUsed > maxOffset,
consumedScroll = consumedScroll,
+ composedButNotVisibleItems = notUsedButComposedItems,
layoutWidth = layoutWidth,
layoutHeight = layoutHeight,
placementBlock = {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasureResult.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasureResult.kt
index aa59a7a..773c0f7 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasureResult.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasureResult.kt
@@ -31,6 +31,8 @@
val canScrollForward: Boolean,
/** The amount of scroll consumed during the measure pass.*/
val consumedScroll: Float,
+ /** List of items which were composed, but are not a part of [visibleItemsInfo].*/
+ val composedButNotVisibleItems: List<LazyMeasuredItem>?,
// properties to be used by the Layout's measure result
/** The calculated layout width */
val layoutWidth: Int,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrolling.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrolling.kt
index cd3157f..1ddc32e 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrolling.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListScrolling.kt
@@ -70,7 +70,7 @@
sequentialAnimation = (anim.velocity != 0f)
) {
// If we haven't found the item yet, check if it's visible.
- val targetItem = getTargetItem()
+ var targetItem = getTargetItem()
if (targetItem == null) {
// Springs can overshoot their target, clamp to the desired range
@@ -85,43 +85,48 @@
}
val consumed = scrollBy(delta)
- if (delta != consumed) {
- debugLog { "Hit end" }
- cancelAnimation()
- loop = false
- return@animateTo
- }
- prevValue += delta
- if (forward) {
- if (value > boundDistancePx) {
- debugLog { "Struck bound going forward" }
- cancelAnimation()
- }
+ targetItem = getTargetItem()
+ if (targetItem != null) {
+ debugLog { "Found the item after performing scrollBy()" }
} else {
- if (value < -boundDistancePx) {
- debugLog { "Struck bound going backward" }
+ if (delta != consumed) {
+ debugLog { "Hit end without finding the item" }
cancelAnimation()
+ loop = false
+ return@animateTo
}
- }
+ prevValue += delta
+ if (forward) {
+ if (value > boundDistancePx) {
+ debugLog { "Struck bound going forward" }
+ cancelAnimation()
+ }
+ } else {
+ if (value < -boundDistancePx) {
+ debugLog { "Struck bound going backward" }
+ cancelAnimation()
+ }
+ }
- // Magic constants for teleportation chosen arbitrarily by experiment
- if (forward) {
- if (
- loops >= 2 &&
- index - layoutInfo.visibleItemsInfo.last().index > 100
- ) {
- // Teleport
- debugLog { "Teleport forward" }
- snapToItemIndexInternal(index = index - 100, scrollOffset = 0)
- }
- } else {
- if (
- loops >= 2 &&
- layoutInfo.visibleItemsInfo.first().index - index > 100
- ) {
- // Teleport
- debugLog { "Teleport backward" }
- snapToItemIndexInternal(index = index + 100, scrollOffset = 0)
+ // Magic constants for teleportation chosen arbitrarily by experiment
+ if (forward) {
+ if (
+ loops >= 2 &&
+ index - layoutInfo.visibleItemsInfo.last().index > 100
+ ) {
+ // Teleport
+ debugLog { "Teleport forward" }
+ snapToItemIndexInternal(index = index - 100, scrollOffset = 0)
+ }
+ } else {
+ if (
+ loops >= 2 &&
+ layoutInfo.visibleItemsInfo.first().index - index > 100
+ ) {
+ // Teleport
+ debugLog { "Teleport backward" }
+ snapToItemIndexInternal(index = index + 100, scrollOffset = 0)
+ }
}
}
}
diff --git a/compose/integration-tests/docs-snippets/lint-baseline.xml b/compose/integration-tests/docs-snippets/lint-baseline.xml
deleted file mode 100644
index 42a176b..0000000
--- a/compose/integration-tests/docs-snippets/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.0.0-alpha15" type="baseline" client="cli" name="Lint" variant="all" version="7.0.0-alpha15">
-
-</issues>
diff --git a/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/MaterialTextField.kt b/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/MaterialTextField.kt
index 585bead..4c44b76 100644
--- a/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/MaterialTextField.kt
+++ b/compose/material/material/integration-tests/material-demos/src/main/java/androidx/compose/material/demos/MaterialTextField.kt
@@ -137,7 +137,7 @@
TextField(
value = text.value,
onValueChange = { text.value = it },
- label = { if (label.value) Text("Label") },
+ label = if (label.value) { @Composable { Text("Label") } } else null,
singleLine = singleLine.value,
modifier = textFieldModifier
)
@@ -145,7 +145,7 @@
OutlinedTextField(
value = text.value,
onValueChange = { text.value = it },
- label = { if (label.value) Text("Label") },
+ label = if (label.value) { @Composable { Text("Label") } } else null,
singleLine = singleLine.value,
modifier = textFieldModifier
)
@@ -179,11 +179,15 @@
"Label" + if (selectedOption == Option.Error) "*" else ""
Text(text = label)
},
- leadingIcon = {
- if (leadingChecked) Icon(Icons.Filled.Favorite, "Favorite")
+ leadingIcon = if (leadingChecked) {
+ @Composable { Icon(Icons.Filled.Favorite, "Favorite") }
+ } else {
+ null
},
- trailingIcon = {
- if (trailingChecked) Icon(Icons.Filled.Info, "Info")
+ trailingIcon = if (trailingChecked) {
+ @Composable { Icon(Icons.Filled.Info, "Info") }
+ } else {
+ null
},
isError = selectedOption == Option.Error,
modifier = Modifier.requiredWidth(300.dp)
@@ -200,11 +204,15 @@
"Label" + if (selectedOption == Option.Error) "*" else ""
Text(text = label)
},
- leadingIcon = {
- if (leadingChecked) Icon(Icons.Filled.Favorite, "Favorite")
+ leadingIcon = if (leadingChecked) {
+ @Composable { Icon(Icons.Filled.Favorite, "Favorite") }
+ } else {
+ null
},
- trailingIcon = {
- if (trailingChecked) Icon(Icons.Filled.Info, "Info")
+ trailingIcon = if (trailingChecked) {
+ @Composable { Icon(Icons.Filled.Info, "Info") }
+ } else {
+ null
},
isError = selectedOption == Option.Error,
modifier = Modifier.requiredWidth(300.dp)
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
index d34da604..998ebaf 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/SliderTest.kt
@@ -391,6 +391,37 @@
}
@Test
+ fun slider_valueChangeFinished_calledOnce() {
+ val state = mutableStateOf(0f)
+ val callCount = mutableStateOf(0)
+
+ rule.setMaterialContent {
+ Slider(
+ modifier = Modifier.testTag(tag),
+ value = state.value,
+ onValueChangeFinished = {
+ callCount.value += 1
+ },
+ onValueChange = { state.value = it }
+ )
+ }
+
+ rule.runOnIdle {
+ Truth.assertThat(callCount.value).isEqualTo(0)
+ }
+
+ rule.onNodeWithTag(tag).performGesture {
+ down(center)
+ moveBy(Offset(50f, 50f))
+ up()
+ }
+
+ rule.runOnIdle {
+ Truth.assertThat(callCount.value).isEqualTo(1)
+ }
+ }
+
+ @Test
fun slider_interactionSource_resetWhenDisposed() {
val interactionSource = MutableInteractionSource()
var emitSlider by mutableStateOf(true)
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 24ea3e2..7c6cb2c 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
@@ -30,6 +30,8 @@
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Divider
+import androidx.compose.material.Icon
+import androidx.compose.material.IconButton
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.LocalContentColor
import androidx.compose.material.LocalTextStyle
@@ -39,6 +41,8 @@
import androidx.compose.material.Text
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.TextFieldPadding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.runOnIdleWithDensity
import androidx.compose.material.setMaterialContent
import androidx.compose.material.setMaterialContentForSizeAssertions
@@ -115,7 +119,6 @@
OutlinedTextField(
value = "input",
onValueChange = {},
- label = {},
modifier = Modifier.requiredWidth(40.dp)
)
}
@@ -127,8 +130,7 @@
rule.setMaterialContentForSizeAssertions {
OutlinedTextField(
value = "input",
- onValueChange = {},
- label = {}
+ onValueChange = {}
)
}
.assertWidthIsEqualTo(ExpectedDefaultTextFieldWidth)
@@ -149,16 +151,14 @@
.testTag(textField1Tag)
.onFocusChanged { textField1Focused = it.isFocused },
value = "input1",
- onValueChange = {},
- label = {}
+ onValueChange = {}
)
OutlinedTextField(
modifier = Modifier
.testTag(textField2Tag)
.onFocusChanged { textField2Focused = it.isFocused },
value = "input2",
- onValueChange = {},
- label = {}
+ onValueChange = {}
)
}
}
@@ -188,8 +188,7 @@
.testTag(TextfieldTag)
.onFocusChanged { focused = it.isFocused },
value = "input",
- onValueChange = {},
- label = {}
+ onValueChange = {}
)
}
}
@@ -434,7 +433,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = "",
onValueChange = {},
- label = {},
placeholder = {
Text(
text = "placeholder",
@@ -460,9 +458,7 @@
ExpectedPadding.roundToPx().toFloat()
)
// placeholder is placed with fixed padding plus additional 8.dp padding on top
- assertThat(placeholderPosition.value?.y).isEqualTo(
- TextFieldPadding.roundToPx() + 8.dp.roundToPx()
- )
+ assertThat(placeholderPosition.value?.y).isEqualTo(TextFieldPadding.roundToPx())
}
}
@@ -476,7 +472,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = "input",
onValueChange = {},
- label = {},
placeholder = {
Text(
text = "placeholder",
@@ -506,7 +501,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = "",
onValueChange = {},
- label = {},
placeholder = {
Text("placeholder")
assertThat(
@@ -530,62 +524,202 @@
}
@Test
- fun testOutlinedTextField_trailingAndLeading_sizeAndPosition() {
+ fun testOutlinedTextField_trailingAndLeading_sizeAndPosition_defaultIcon() {
val textFieldWidth = 300.dp
- val size = 30.dp
val leadingPosition = Ref<Offset>()
val leadingSize = Ref<IntSize>()
val trailingPosition = Ref<Offset>()
val trailingSize = Ref<IntSize>()
-
+ val density = Density(2f)
rule.setMaterialContent {
- OutlinedTextField(
- value = "text",
- onValueChange = {},
- modifier = Modifier.width(textFieldWidth),
- label = {},
- leadingIcon = {
- Box(
- Modifier.size(size).onGloballyPositioned {
- leadingPosition.value = it.positionInRoot()
- leadingSize.value = it.size
- }
- )
- },
- trailingIcon = {
- Box(
- Modifier.size(size).onGloballyPositioned {
- trailingPosition.value = it.positionInRoot()
- trailingSize.value = it.size
- }
- )
- }
- )
+ CompositionLocalProvider(LocalDensity provides density) {
+ OutlinedTextField(
+ value = "text",
+ onValueChange = {},
+ modifier = Modifier.width(textFieldWidth),
+ label = { Text("label") },
+ leadingIcon = {
+ Icon(
+ Icons.Default.Favorite,
+ null,
+ Modifier.onGloballyPositioned {
+ leadingPosition.value = it.positionInRoot()
+ leadingSize.value = it.size
+ }
+ )
+ },
+ trailingIcon = {
+ Icon(
+ Icons.Default.Favorite,
+ null,
+ Modifier.onGloballyPositioned {
+ trailingPosition.value = it.positionInRoot()
+ trailingSize.value = it.size
+ }
+ )
+ },
+ )
+ }
}
- rule.runOnIdleWithDensity {
- val minimumHeight = ExpectedMinimumTextFieldHeight.roundToPx()
- // leading
- assertThat(leadingSize.value).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
- assertThat(leadingPosition.value?.x).isEqualTo(IconPadding.roundToPx().toFloat())
- assertThat(leadingPosition.value?.y).isEqualTo(
- ((minimumHeight - leadingSize.value!!.height) / 2f).roundToInt() + 8.dp.roundToPx()
- )
- // trailing
- assertThat(trailingSize.value).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
- assertThat(trailingPosition.value?.x).isEqualTo(
- (textFieldWidth.roundToPx() - IconPadding.roundToPx() - trailingSize.value!!.width)
- .toFloat()
- )
- assertThat(trailingPosition.value?.y).isEqualTo(
- ((minimumHeight - trailingSize.value!!.height) / 2f).roundToInt() + 8.dp.roundToPx()
- )
+ rule.runOnIdle {
+ with(density) {
+ val minimumHeight = ExpectedMinimumTextFieldHeight.roundToPx()
+ val size = 24.dp // default icon size
+ // leading
+ assertThat(leadingSize.value).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
+ assertThat(leadingPosition.value?.x).isEqualTo(IconPadding.roundToPx().toFloat())
+ assertThat(leadingPosition.value?.y).isEqualTo(
+ ((minimumHeight - leadingSize.value!!.height) / 2f).roundToInt() +
+ 8.dp.roundToPx()
+ )
+ // trailing
+ assertThat(trailingSize.value).isEqualTo(
+ IntSize(
+ size.roundToPx(),
+ size.roundToPx()
+ )
+ )
+ assertThat(trailingPosition.value?.x).isEqualTo(
+ (
+ textFieldWidth.roundToPx() - IconPadding.roundToPx() -
+ trailingSize.value!!.width
+ ).toFloat()
+ )
+ assertThat(trailingPosition.value?.y).isEqualTo(
+ ((minimumHeight - trailingSize.value!!.height) / 2f).roundToInt() +
+ 8.dp.roundToPx()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOutlinedTextField_trailingAndLeading_sizeAndPosition_defaultIconButton() {
+ val textFieldWidth = 300.dp
+ val textFieldHeight = 80.dp
+ val density = Density(2f)
+
+ var leadingPosition: Offset? = null
+ var leadingSize: IntSize? = null
+ var trailingPosition: Offset? = null
+ var trailingSize: IntSize? = null
+
+ rule.setMaterialContent {
+ CompositionLocalProvider(LocalDensity provides density) {
+ OutlinedTextField(
+ value = "text",
+ onValueChange = {},
+ modifier = Modifier.width(textFieldWidth).height(textFieldHeight),
+ leadingIcon = {
+ IconButton(
+ onClick = {},
+ modifier = Modifier.onGloballyPositioned {
+ leadingPosition = it.positionInRoot()
+ leadingSize = it.size
+ }
+ ) { Icon(Icons.Default.Favorite, null) }
+ },
+ trailingIcon = {
+ IconButton(
+ onClick = {},
+ modifier = Modifier.onGloballyPositioned {
+ trailingPosition = it.positionInRoot()
+ trailingSize = it.size
+ }
+ ) { Icon(Icons.Default.Favorite, null) }
+ }
+ )
+ }
+ }
+
+ rule.runOnIdle {
+ val size = 48.dp // default IconButton size
+
+ with(density) {
+ // leading
+ assertThat(leadingSize).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
+ assertThat(leadingPosition?.x).isEqualTo(0f)
+ assertThat(leadingPosition?.y).isEqualTo(
+ ((textFieldHeight.roundToPx() - leadingSize!!.height) / 2f).roundToInt()
+ )
+ // trailing
+ assertThat(trailingSize).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
+ assertThat(trailingPosition?.x).isEqualTo(
+ (textFieldWidth.roundToPx() - trailingSize!!.width).toFloat()
+ )
+ assertThat(trailingPosition?.y).isEqualTo(
+ ((textFieldHeight.roundToPx() - trailingSize!!.height) / 2f).roundToInt()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testOutlinedTextField_trailingAndLeading_sizeAndPosition_nonDefaultSizeIcon() {
+ val textFieldWidth = 300.dp
+ val textFieldHeight = 80.dp
+ val size = 72.dp
+ val density = Density(2f)
+
+ var leadingPosition: Offset? = null
+ var leadingSize: IntSize? = null
+ var trailingPosition: Offset? = null
+ var trailingSize: IntSize? = null
+
+ rule.setMaterialContent {
+ CompositionLocalProvider(LocalDensity provides density) {
+ OutlinedTextField(
+ value = "text",
+ onValueChange = {},
+ modifier = Modifier.width(textFieldWidth).height(textFieldHeight),
+ leadingIcon = {
+ Box(
+ Modifier.size(size).onGloballyPositioned {
+ leadingPosition = it.positionInRoot()
+ leadingSize = it.size
+ }
+ )
+ },
+ trailingIcon = {
+ Box(
+ Modifier.size(size).onGloballyPositioned {
+ trailingPosition = it.positionInRoot()
+ trailingSize = it.size
+ }
+ )
+ },
+ )
+ }
+ }
+
+ rule.runOnIdle {
+ with(density) {
+ // leading
+ assertThat(leadingSize).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
+ assertThat(leadingPosition?.x).isEqualTo(0f)
+ assertThat(leadingPosition?.y).isEqualTo(
+ ((textFieldHeight.roundToPx() - leadingSize!!.height) / 2f).roundToInt()
+ )
+ // trailing
+ assertThat(trailingSize).isEqualTo(
+ IntSize(
+ size.roundToPx(),
+ size.roundToPx()
+ )
+ )
+ assertThat(trailingPosition?.x).isEqualTo(
+ (textFieldWidth.roundToPx() - trailingSize!!.width).toFloat()
+ )
+ assertThat(trailingPosition?.y).isEqualTo(
+ ((textFieldHeight.roundToPx() - trailingSize!!.height) / 2f).roundToInt()
+ )
+ }
}
}
@Test
fun testOutlinedTextField_labelPositionX_initial_withTrailingAndLeading() {
- val iconSize = 30.dp
val labelPosition = Ref<Offset>()
rule.setMaterialContent {
Box {
@@ -600,13 +734,14 @@
}
)
},
- trailingIcon = { Box(Modifier.size(iconSize)) },
- leadingIcon = { Box(Modifier.size(iconSize)) }
+ trailingIcon = { Icon(Icons.Default.Favorite, null) },
+ leadingIcon = { Icon(Icons.Default.Favorite, null) }
)
}
}
rule.runOnIdleWithDensity {
+ val iconSize = 24.dp // default icon size
assertThat(labelPosition.value?.x).isEqualTo(
(ExpectedPadding.roundToPx() + IconPadding.roundToPx() + iconSize.roundToPx())
.toFloat()
@@ -615,7 +750,7 @@
}
@Test
- fun testOutlinedTextField_labelPositionX_initial_withEmptyTrailingAndLeading() {
+ fun testOutlinedTextField_labelPositionX_initial_withNullTrailingAndLeading() {
val labelPosition = Ref<Offset>()
rule.setMaterialContent {
Box {
@@ -630,8 +765,8 @@
}
)
},
- trailingIcon = {},
- leadingIcon = {}
+ trailingIcon = null,
+ leadingIcon = null
)
}
}
@@ -649,7 +784,6 @@
OutlinedTextField(
value = "",
onValueChange = {},
- label = {},
isError = false,
leadingIcon = {
assertThat(LocalContentColor.current)
@@ -677,7 +811,6 @@
OutlinedTextField(
value = "",
onValueChange = {},
- label = {},
isError = true,
leadingIcon = {
assertThat(LocalContentColor.current)
@@ -707,7 +840,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = text.value,
onValueChange = { text.value = it },
- label = {},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Go,
keyboardType = KeyboardType.Email
@@ -743,7 +875,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = "qwerty",
onValueChange = {},
- label = {},
visualTransformation = PasswordVisualTransformation('\u0020')
)
}
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 600912f..7a06730 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
@@ -38,6 +38,7 @@
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Divider
import androidx.compose.material.Icon
+import androidx.compose.material.IconButton
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.LocalContentColor
import androidx.compose.material.LocalTextStyle
@@ -70,6 +71,7 @@
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.node.Ref
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.LocalTextInputService
import androidx.compose.ui.platform.LocalView
@@ -101,6 +103,7 @@
import androidx.compose.ui.text.input.TextInputService
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -145,7 +148,6 @@
TextField(
value = "input",
onValueChange = {},
- label = {},
modifier = Modifier.height(20.dp)
)
}
@@ -158,7 +160,6 @@
TextField(
value = "input",
onValueChange = {},
- label = {},
modifier = Modifier.requiredWidth(40.dp)
)
}
@@ -170,8 +171,7 @@
rule.setMaterialContentForSizeAssertions {
TextField(
value = "input",
- onValueChange = {},
- label = {}
+ onValueChange = {}
)
}
.assertWidthIsEqualTo(ExpectedDefaultTextFieldWidth)
@@ -193,14 +193,12 @@
modifier = Modifier.testTag(textField1Tag),
value = "input1",
onValueChange = {},
- label = {},
interactionSource = interactionSource1
)
TextField(
modifier = Modifier.testTag(textField2Tag),
value = "input2",
onValueChange = {},
- label = {},
interactionSource = interactionSource2
)
}
@@ -251,7 +249,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = "input",
onValueChange = {},
- label = {},
interactionSource = interactionSource
)
}
@@ -292,8 +289,7 @@
.focusRequester(focusRequester)
.testTag(TextfieldTag),
value = "input",
- onValueChange = {},
- label = {}
+ onValueChange = {}
)
}
}
@@ -324,8 +320,7 @@
.focusRequester(focusRequester)
.testTag(TextfieldTag),
value = "input",
- onValueChange = {},
- label = {}
+ onValueChange = {}
)
}
}
@@ -603,7 +598,6 @@
modifier = Modifier.height(height).testTag(TextfieldTag),
value = "",
onValueChange = {},
- label = {},
placeholder = {
Text(
text = "placeholder",
@@ -645,7 +639,7 @@
modifier = Modifier.testTag(TextfieldTag),
value = "input",
onValueChange = {},
- label = {},
+
placeholder = {
Text(
text = "placeholder",
@@ -675,7 +669,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = "",
onValueChange = {},
- label = {},
placeholder = {
Text("placeholder")
assertThat(
@@ -699,66 +692,213 @@
}
@Test
- fun testTextField_trailingAndLeading_sizeAndPosition() {
+ fun testTextField_trailingAndLeading_sizeAndPosition_defaultIcon() {
val textFieldHeight = 60.dp
val textFieldWidth = 300.dp
- val size = 30.dp
val leadingPosition = Ref<Offset>()
val leadingSize = Ref<IntSize>()
val trailingPosition = Ref<Offset>()
val trailingSize = Ref<IntSize>()
+ val density = Density(2f)
rule.setMaterialContent {
- TextField(
- value = "text",
- onValueChange = {},
- modifier = Modifier.size(textFieldWidth, textFieldHeight),
- label = {},
- leadingIcon = {
- Box(
- Modifier.size(size).onGloballyPositioned {
- leadingPosition.value = it.positionInRoot()
- leadingSize.value = it.size
- }
- )
- },
- trailingIcon = {
- Box(
- Modifier.size(size).onGloballyPositioned {
- trailingPosition.value = it.positionInRoot()
- trailingSize.value = it.size
- }
- )
- }
- )
+ CompositionLocalProvider(LocalDensity provides density) {
+ TextField(
+ value = "text",
+ onValueChange = {},
+ modifier = Modifier.size(textFieldWidth, textFieldHeight),
+ leadingIcon = {
+ Icon(
+ Icons.Default.Favorite,
+ null,
+ Modifier.onGloballyPositioned {
+ leadingPosition.value = it.positionInRoot()
+ leadingSize.value = it.size
+ }
+ )
+ },
+ trailingIcon = {
+ Icon(
+ Icons.Default.Favorite,
+ null,
+ Modifier.onGloballyPositioned {
+ trailingPosition.value = it.positionInRoot()
+ trailingSize.value = it.size
+ }
+ )
+ }
+ )
+ }
}
- rule.runOnIdleWithDensity {
- // leading
- assertThat(leadingSize.value).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
- assertThat(leadingPosition.value?.x).isEqualTo(IconPadding.roundToPx().toFloat())
- assertThat(leadingPosition.value?.y).isEqualTo(
- ((textFieldHeight.roundToPx() - leadingSize.value!!.height) / 2f).roundToInt()
- .toFloat()
- )
- // trailing
- assertThat(trailingSize.value).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
- assertThat(trailingPosition.value?.x).isEqualTo(
- (textFieldWidth.roundToPx() - IconPadding.roundToPx() - trailingSize.value!!.width)
- .toFloat()
- )
- assertThat(trailingPosition.value?.y)
- .isEqualTo(
- ((textFieldHeight.roundToPx() - trailingSize.value!!.height) / 2f)
- .roundToInt().toFloat()
+ rule.runOnIdle {
+ val size = 24.dp // default icon size
+ with(density) {
+ // leading
+ assertThat(leadingSize.value).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
+ assertThat(leadingPosition.value?.x).isEqualTo(IconPadding.roundToPx().toFloat())
+ assertThat(leadingPosition.value?.y).isEqualTo(
+ ((textFieldHeight.roundToPx() - leadingSize.value!!.height) / 2f).roundToInt()
+ .toFloat()
)
+ // trailing
+ assertThat(trailingSize.value).isEqualTo(
+ IntSize(
+ size.roundToPx(),
+ size.roundToPx()
+ )
+ )
+ assertThat(trailingPosition.value?.x).isEqualTo(
+ (
+ textFieldWidth.roundToPx() - IconPadding.roundToPx() -
+ trailingSize.value!!.width
+ ).toFloat()
+ )
+ assertThat(trailingPosition.value?.y)
+ .isEqualTo(
+ ((textFieldHeight.roundToPx() - trailingSize.value!!.height) / 2f)
+ .roundToInt().toFloat()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testTextField_trailingAndLeading_sizeAndPosition_iconButton() {
+ val textFieldHeight = 80.dp
+ val textFieldWidth = 300.dp
+ val density = Density(2f)
+
+ var leadingPosition: Offset? = null
+ var leadingSize: IntSize? = null
+ var trailingPosition: Offset? = null
+ var trailingSize: IntSize? = null
+
+ rule.setMaterialContent {
+ CompositionLocalProvider(LocalDensity provides density) {
+ TextField(
+ value = "text",
+ onValueChange = {},
+ modifier = Modifier.size(textFieldWidth, textFieldHeight),
+ leadingIcon = {
+ IconButton(
+ onClick = {},
+ modifier = Modifier.onGloballyPositioned {
+ leadingPosition = it.positionInRoot()
+ leadingSize = it.size
+ }
+ ) {
+ Icon(Icons.Default.Favorite, null)
+ }
+ },
+ trailingIcon = {
+ IconButton(
+ onClick = {},
+ modifier = Modifier.onGloballyPositioned {
+ trailingPosition = it.positionInRoot()
+ trailingSize = it.size
+ }
+ ) {
+ Icon(Icons.Default.Favorite, null)
+ }
+ }
+ )
+ }
+ }
+
+ rule.runOnIdle {
+ val size = 48.dp // default IconButton size
+
+ with(density) {
+ // leading
+ assertThat(leadingSize).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
+ assertThat(leadingPosition?.x).isEqualTo(0f)
+ assertThat(leadingPosition?.y).isEqualTo(
+ ((textFieldHeight.roundToPx() - leadingSize!!.height) / 2f).roundToInt()
+ .toFloat()
+ )
+ // trailing
+ assertThat(trailingSize).isEqualTo(
+ IntSize(size.roundToPx(), size.roundToPx())
+ )
+ assertThat(trailingPosition?.x).isEqualTo(
+ (textFieldWidth.roundToPx() - trailingSize!!.width).toFloat()
+ )
+ assertThat(trailingPosition?.y)
+ .isEqualTo(
+ ((textFieldHeight.roundToPx() - trailingSize!!.height) / 2f)
+ .roundToInt().toFloat()
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testTextField_trailingAndLeading_sizeAndPosition_nonDefaultSizeIcon() {
+ val textFieldHeight = 80.dp
+ val textFieldWidth = 300.dp
+ val density = Density(2f)
+ val size = 70.dp
+
+ var leadingPosition: Offset? = null
+ var leadingSize: IntSize? = null
+ var trailingPosition: Offset? = null
+ var trailingSize: IntSize? = null
+
+ rule.setMaterialContent {
+ CompositionLocalProvider(LocalDensity provides density) {
+ TextField(
+ value = "text",
+ onValueChange = {},
+ modifier = Modifier.size(textFieldWidth, textFieldHeight),
+ leadingIcon = {
+ Box(
+ Modifier.size(size).onGloballyPositioned {
+ leadingPosition = it.positionInRoot()
+ leadingSize = it.size
+ }
+ )
+ },
+ trailingIcon = {
+ Box(
+ Modifier.size(size).onGloballyPositioned {
+ trailingPosition = it.positionInRoot()
+ trailingSize = it.size
+ }
+ )
+ }
+ )
+ }
+ }
+
+ rule.runOnIdle {
+ with(density) {
+ // leading
+ assertThat(leadingSize).isEqualTo(IntSize(size.roundToPx(), size.roundToPx()))
+ assertThat(leadingPosition?.x).isEqualTo(0f)
+ assertThat(leadingPosition?.y).isEqualTo(
+ ((textFieldHeight.roundToPx() - leadingSize!!.height) / 2f).roundToInt()
+ .toFloat()
+ )
+ // trailing
+ assertThat(trailingSize).isEqualTo(
+ IntSize(size.roundToPx(), size.roundToPx())
+ )
+ assertThat(trailingPosition?.x).isEqualTo(
+ (textFieldWidth.roundToPx() - trailingSize!!.width).toFloat()
+ )
+ assertThat(trailingPosition?.y)
+ .isEqualTo(
+ ((textFieldHeight.roundToPx() - trailingSize!!.height) / 2f)
+ .roundToInt().toFloat()
+ )
+ }
}
}
@Test
fun testTextField_labelPositionX_initial_withTrailingAndLeading() {
val height = 60.dp
- val iconSize = 30.dp
val labelPosition = Ref<Offset>()
rule.setMaterialContent {
Box {
@@ -774,13 +914,14 @@
}
)
},
- trailingIcon = { Box(Modifier.size(iconSize)) },
- leadingIcon = { Box(Modifier.size(iconSize)) }
+ trailingIcon = { Icon(Icons.Default.Favorite, null) },
+ leadingIcon = { Icon(Icons.Default.Favorite, null) }
)
}
}
rule.runOnIdleWithDensity {
+ val iconSize = 24.dp // default icon size
assertThat(labelPosition.value?.x).isEqualTo(
(ExpectedPadding.roundToPx() + IconPadding.roundToPx() + iconSize.roundToPx())
.toFloat()
@@ -789,7 +930,7 @@
}
@Test
- fun testTextField_labelPositionX_initial_withEmptyTrailingAndLeading() {
+ fun testTextField_labelPositionX_initial_withNullTrailingAndLeading() {
val height = 60.dp
val labelPosition = Ref<Offset>()
rule.setMaterialContent {
@@ -806,8 +947,8 @@
}
)
},
- trailingIcon = {},
- leadingIcon = {}
+ trailingIcon = null,
+ leadingIcon = null
)
}
}
@@ -825,7 +966,6 @@
TextField(
value = "",
onValueChange = {},
- label = {},
isError = false,
leadingIcon = {
assertThat(LocalContentColor.current)
@@ -853,7 +993,6 @@
TextField(
value = "",
onValueChange = {},
- label = {},
isError = true,
leadingIcon = {
assertThat(LocalContentColor.current)
@@ -883,7 +1022,6 @@
modifier = Modifier.testTag(TextfieldTag),
value = text.value,
onValueChange = { text.value = it },
- label = {},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Go,
keyboardType = KeyboardType.Email
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
index 0837cb5..4805fb8 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
@@ -403,7 +403,10 @@
)
if (leading != null) {
- Box(Modifier.layoutId(LeadingId).iconPadding(start = HorizontalIconPadding)) {
+ Box(
+ modifier = Modifier.layoutId(LeadingId).then(IconDefaultSizeModifier),
+ contentAlignment = Alignment.Center
+ ) {
Decoration(
contentColor = leadingColor,
content = leading
@@ -411,19 +414,27 @@
}
}
if (trailing != null) {
- Box(Modifier.layoutId(TrailingId).iconPadding(end = HorizontalIconPadding)) {
+ Box(
+ modifier = Modifier.layoutId(TrailingId).then(IconDefaultSizeModifier),
+ contentAlignment = Alignment.Center
+ ) {
Decoration(
contentColor = trailingColor,
content = trailing
)
}
}
+ val paddingToIcon = TextFieldPadding - HorizontalIconPadding
+ val padding = Modifier.padding(
+ start = if (leading != null) paddingToIcon else TextFieldPadding,
+ end = if (trailing != null) paddingToIcon else TextFieldPadding
+ )
if (placeholder != null) {
- placeholder(Modifier.layoutId(PlaceholderId).padding(horizontal = TextFieldPadding))
+ placeholder(Modifier.layoutId(PlaceholderId).then(padding))
}
Box(
- modifier = Modifier.layoutId(TextFieldId).padding(horizontal = TextFieldPadding),
+ modifier = Modifier.layoutId(TextFieldId).then(padding),
propagateMinConstraints = true
) {
textField()
@@ -603,6 +614,7 @@
density: Float
) {
val topBottomPadding = (TextFieldPadding.value * density).roundToInt()
+ val iconPadding = HorizontalIconPadding.value * density
// placed center vertically and to the start edge horizontally
leadingPlaceable?.placeRelative(
@@ -626,9 +638,14 @@
}
val positionY =
startPositionY * (1 - animationProgress) - (it.height / 2) * animationProgress
- val positionX = (TextFieldPadding.value * density) +
- widthOrZero(leadingPlaceable) * (1 - animationProgress)
- it.placeRelative(positionX.roundToInt(), positionY.roundToInt())
+ val positionX = (
+ if (leadingPlaceable == null) {
+ 0f
+ } else {
+ (widthOrZero(leadingPlaceable) - iconPadding) * (1 - animationProgress)
+ }
+ ).roundToInt() + topBottomPadding
+ it.placeRelative(positionX, positionY.roundToInt())
}
// placed center vertically and after the leading icon horizontally if single line text field
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
index 090084f..054d49f 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
@@ -182,7 +182,8 @@
animateToTarget(draggableState, current, target, velocity)
onValueChangeFinished?.invoke()
}
- } else {
+ } else if (!draggableState.isDragging) {
+ // check ifDragging in case the change is still in progress (touch -> drag case)
onValueChangeFinished?.invoke()
}
}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
index 6d0ea40..f370a43 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
@@ -404,7 +404,10 @@
Layout(
content = {
if (leading != null) {
- Box(Modifier.layoutId(LeadingId).iconPadding(start = HorizontalIconPadding)) {
+ Box(
+ modifier = Modifier.layoutId(LeadingId).then(IconDefaultSizeModifier),
+ contentAlignment = Alignment.Center
+ ) {
Decoration(
contentColor = leadingColor,
content = leading
@@ -412,26 +415,27 @@
}
}
if (trailing != null) {
- Box(Modifier.layoutId(TrailingId).iconPadding(end = HorizontalIconPadding)) {
+ Box(
+ modifier = Modifier.layoutId(TrailingId).then(IconDefaultSizeModifier),
+ contentAlignment = Alignment.Center
+ ) {
Decoration(
contentColor = trailingColor,
content = trailing
)
}
}
- val padding = Modifier.padding(horizontal = TextFieldPadding)
+
+ val paddingToIcon = TextFieldPadding - HorizontalIconPadding
+ val padding = Modifier.padding(
+ start = if (leading != null) paddingToIcon else TextFieldPadding,
+ end = if (trailing != null) paddingToIcon else TextFieldPadding
+ )
if (placeholder != null) {
placeholder(Modifier.layoutId(PlaceholderId).then(padding))
}
if (label != null) {
- Box(
- modifier = Modifier
- .layoutId(LabelId)
- .iconPadding(
- start = TextFieldPadding,
- end = TextFieldPadding
- )
- ) { label() }
+ Box(Modifier.layoutId(LabelId).then(padding)) { label() }
}
Box(
modifier = Modifier.layoutId(TextFieldId).then(padding),
@@ -529,7 +533,7 @@
)
return layout(width, height) {
- if (widthOrZero(labelPlaceable) != 0) {
+ if (labelPlaceable != null) {
// label's final position is always relative to the baseline
val labelEndPosition = (baseLineOffset - lastBaseline).coerceAtLeast(0)
placeWithLabel(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
index 01b48f06..77eb085 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
@@ -25,6 +25,7 @@
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Strings.DefaultErrorMessage
@@ -37,24 +38,15 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.takeOrElse
-import androidx.compose.ui.layout.LayoutModifier
-import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureResult
-import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.layout.Placeable
-import androidx.compose.ui.platform.InspectorValueInfo
-import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.semantics.error
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.lerp
-import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.constrainWidth
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.offset
internal enum class TextFieldType {
Filled, Outlined
@@ -233,37 +225,6 @@
internal fun widthOrZero(placeable: Placeable?) = placeable?.width ?: 0
internal fun heightOrZero(placeable: Placeable?) = placeable?.height ?: 0
-/**
- * A modifier that applies padding only if the size of the element is not zero
- */
-internal fun Modifier.iconPadding(start: Dp = 0.dp, end: Dp = 0.dp) =
- this.then(
- @Suppress("ModifierInspectorInfo")
- object : LayoutModifier, InspectorValueInfo(
- debugInspectorInfo {
- name = "iconPadding"
- properties["start"] = start
- properties["end"] = end
- }
- ) {
- override fun MeasureScope.measure(
- measurable: Measurable,
- constraints: Constraints
- ): MeasureResult {
- val horizontal = start.roundToPx() + end.roundToPx()
- val placeable = measurable.measure(constraints.offset(-horizontal))
- val width = if (placeable.nonZero) {
- constraints.constrainWidth(placeable.width + horizontal)
- } else {
- 0
- }
- return layout(width, placeable.height) {
- placeable.placeRelative(start.roundToPx(), 0)
- }
- }
- }
- )
-
private object TextFieldTransitionScope {
@Composable
fun Transition(
@@ -363,3 +324,5 @@
private val IndicatorFocusedWidth = 2.dp
internal val TextFieldPadding = 16.dp
internal val HorizontalIconPadding = 12.dp
+
+internal val IconDefaultSizeModifier = Modifier.defaultMinSize(48.dp, 48.dp)
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ReadOnlyComposable.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ReadOnlyComposable.kt
index 2bdb54c..e0d3685 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ReadOnlyComposable.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/ReadOnlyComposable.kt
@@ -23,7 +23,7 @@
* This will result in slightly more efficient code.
*
* A common use case for this are for functions that only need to be composable in order to read
- * [Ambient] values, but don't call any other composables.
+ * [CompositionLocal] values, but don't call any other composables.
*
* Caution: Use of this annotation means that the annotated declaration *MUST* comply with this
* contract, or else the resulting code's behavior will be undefined.
diff --git a/compose/test-utils/lint-baseline.xml b/compose/test-utils/lint-baseline.xml
deleted file mode 100644
index 453a386..0000000
--- a/compose/test-utils/lint-baseline.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha01" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha01">
-
- <issue
- id="BanTargetApiAnnotation"
- message="Uses @TargetApi annotation"
- errorLine1="@TargetApi(Build.VERSION_CODES.Q)"
- errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt"
- line="345"
- column="1"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 28; however, the containing class androidx.compose.testutils.AndroidComposeTestCaseRunner is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" bitmap = Bitmap.createBitmap(picture)"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt"
- line="274"
- column="29"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.testutils.RenderNodeCapture is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" private val renderNode = RenderNode("Test")"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt"
- line="347"
- column="30"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.testutils.RenderNodeCapture is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" renderNode.setPosition(0, 0, width, height)"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt"
- line="350"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.testutils.RenderNodeCapture is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return renderNode.beginRecording()"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt"
- line="351"
- column="27"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.testutils.RenderNodeCapture is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" renderNode.endRecording()"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt"
- line="355"
- column="20"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.testutils.ViewCapture_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" decorView.viewTreeObserver.registerFrameCommitCallback {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/ViewCapture.android.kt"
- line="68"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.compose.testutils.ViewCapture_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" PixelCopy.request(windowToCapture, boundsInWindow, destBitmap, onCopyFinished, handler)"
- errorLine2=" ~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/testutils/ViewCapture.android.kt"
- line="104"
- column="15"/>
- </issue>
-
-</issues>
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt b/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt
index 9aad576d..549af41 100644
--- a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt
+++ b/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.android.kt
@@ -30,7 +30,7 @@
import androidx.annotation.RequiresApi
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
-import androidx.compose.runtime.MonotonicFrameClock
+import androidx.annotation.DoNotInline
import androidx.compose.runtime.Recomposer
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.ui.platform.ViewRootForTest
@@ -41,7 +41,6 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineDispatcher
-import java.util.concurrent.atomic.AtomicLong
/**
* Factory method to provide implementation of [ComposeBenchmarkScope].
@@ -87,15 +86,6 @@
private var canvas: Canvas? = null
- private class AutoFrameClock(
- private val singleFrameTimeNanos: Long = 16_000_000
- ) : MonotonicFrameClock {
- private val lastFrameTime = AtomicLong(0L)
-
- override suspend fun <R> withFrameNanos(onFrame: (Long) -> R): R =
- onFrame(lastFrameTime.getAndAdd(singleFrameTimeNanos))
- }
-
private val testCoroutineDispatcher = TestCoroutineDispatcher()
private val frameClock = TestMonotonicFrameClock(CoroutineScope(testCoroutineDispatcher))
private val recomposerApplyCoroutineScope = CoroutineScope(
@@ -271,7 +261,7 @@
val imageView = ImageView(activity)
val bitmap: Bitmap
if (Build.VERSION.SDK_INT >= 28) {
- bitmap = Bitmap.createBitmap(picture)
+ bitmap = BitmapHelper.createBitmap(picture)
} else {
val width = picture.width.coerceAtLeast(1)
val height = picture.height.coerceAtLeast(1)
@@ -383,4 +373,12 @@
renderNode.end(canvas!!)
canvas = null
}
+}
+
+@RequiresApi(28)
+private object BitmapHelper {
+ @DoNotInline
+ fun createBitmap(picture: Picture): Bitmap {
+ return Bitmap.createBitmap(picture)
+ }
}
\ No newline at end of file
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/ViewCapture.android.kt b/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/ViewCapture.android.kt
index 5253670..6dec162 100644
--- a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/ViewCapture.android.kt
+++ b/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/ViewCapture.android.kt
@@ -16,17 +16,20 @@
package androidx.compose.testutils
-import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import android.graphics.Bitmap
+import android.graphics.Rect
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.view.PixelCopy
+import android.view.PixelCopy.OnPixelCopyFinishedListener
import android.view.View
import android.view.ViewTreeObserver
+import android.view.Window
+import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
@@ -41,13 +44,12 @@
* in the bitmap as this is taken from the component's window surface.
*/
@RequiresApi(Build.VERSION_CODES.O)
-@SuppressLint("UnsafeNewApiCall") // Seems like lint is giving false red flags
fun View.captureToImage(): ImageBitmap {
val locationInWindow = intArrayOf(0, 0)
getLocationInWindow(locationInWindow)
val x = locationInWindow[0]
val y = locationInWindow[1]
- val boundsInWindow = android.graphics.Rect(x, y, x + width, y + height)
+ val boundsInWindow = Rect(x, y, x + width, y + height)
fun Context.getActivity(): Activity? {
return when (this) {
@@ -65,7 +67,7 @@
val decorView = windowToCapture.decorView
handler.post {
if (Build.VERSION.SDK_INT >= 29 && decorView.isHardwareAccelerated) {
- decorView.viewTreeObserver.registerFrameCommitCallback {
+ FrameCommitCallbackHelper.registerFrameCommitCallback(decorView.viewTreeObserver) {
drawLatch.countDown()
}
} else {
@@ -97,11 +99,11 @@
val latch = CountDownLatch(1)
var copyResult = 0
- val onCopyFinished = PixelCopy.OnPixelCopyFinishedListener { result ->
+ val onCopyFinished = OnPixelCopyFinishedListener { result ->
copyResult = result
latch.countDown()
}
- PixelCopy.request(windowToCapture, boundsInWindow, destBitmap, onCopyFinished, handler)
+ PixelCopyHelper.request(windowToCapture, boundsInWindow, destBitmap, onCopyFinished, handler)
if (!latch.await(1, TimeUnit.SECONDS)) {
throw AssertionError("Failed waiting for PixelCopy!")
@@ -110,4 +112,26 @@
throw AssertionError("PixelCopy failed!")
}
return destBitmap.asImageBitmap()
+}
+
+@RequiresApi(29)
+private object FrameCommitCallbackHelper {
+ @DoNotInline
+ fun registerFrameCommitCallback(viewTreeObserver: ViewTreeObserver, runnable: Runnable) {
+ viewTreeObserver.registerFrameCommitCallback(runnable)
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.O)
+private object PixelCopyHelper {
+ @DoNotInline
+ fun request(
+ source: Window,
+ srcRect: Rect?,
+ dest: Bitmap,
+ listener: OnPixelCopyFinishedListener,
+ listenerThread: Handler
+ ) {
+ PixelCopy.request(source, srcRect, dest, listener, listenerThread)
+ }
}
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/benchmark/lint-baseline.xml b/compose/ui/ui-graphics/benchmark/lint-baseline.xml
deleted file mode 100644
index 42a176b..0000000
--- a/compose/ui/ui-graphics/benchmark/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.0.0-alpha15" type="baseline" client="cli" name="Lint" variant="all" version="7.0.0-alpha15">
-
-</issues>
diff --git a/compose/ui/ui-graphics/lint-baseline.xml b/compose/ui/ui-graphics/lint-baseline.xml
deleted file mode 100644
index c2ed54b..0000000
--- a/compose/ui/ui-graphics/lint-baseline.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha01" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha01">
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.ui.graphics.AndroidColorFilter_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" BlendModeColorFilter(color.toArgb(), blendMode.toAndroidBlendMode())"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidColorFilter.android.kt"
- line="39"
- column="9"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.ui.graphics.CanvasUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" canvas.enableZ()"
- errorLine2=" ~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/graphics/CanvasUtils.android.kt"
- line="39"
- column="24"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.ui.graphics.CanvasUtils is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" canvas.disableZ()"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/graphics/CanvasUtils.android.kt"
- line="41"
- column="24"/>
- </issue>
-
-</issues>
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidColorFilter.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidColorFilter.android.kt
index 5c53c36..8a24632 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidColorFilter.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidColorFilter.android.kt
@@ -16,10 +16,11 @@
package androidx.compose.ui.graphics
-import android.annotation.SuppressLint
import android.graphics.BlendModeColorFilter
import android.graphics.PorterDuffColorFilter
import android.os.Build
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
internal actual typealias NativeColorFilter = android.graphics.ColorFilter
@@ -34,9 +35,8 @@
fun android.graphics.ColorFilter.asComposeColorFilter(): ColorFilter = ColorFilter(this)
internal actual fun actualTintColorFilter(color: Color, blendMode: BlendMode): ColorFilter {
- @SuppressLint("UnsafeNewApiCall")
val androidColorFilter = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- BlendModeColorFilter(color.toArgb(), blendMode.toAndroidBlendMode())
+ BlendModeColorFilterHelper.BlendModeColorFilter(color, blendMode)
} else {
PorterDuffColorFilter(color.toArgb(), blendMode.toPorterDuffMode())
}
@@ -47,4 +47,12 @@
ColorFilter(android.graphics.ColorMatrixColorFilter(colorMatrix.values))
internal actual fun actualLightingColorFilter(multiply: Color, add: Color): ColorFilter =
- ColorFilter(android.graphics.LightingColorFilter(multiply.toArgb(), add.toArgb()))
\ No newline at end of file
+ ColorFilter(android.graphics.LightingColorFilter(multiply.toArgb(), add.toArgb()))
+
+@RequiresApi(Build.VERSION_CODES.Q)
+private object BlendModeColorFilterHelper {
+ @DoNotInline
+ fun BlendModeColorFilter(color: Color, blendMode: BlendMode): BlendModeColorFilter {
+ return BlendModeColorFilter(color.toArgb(), blendMode.toAndroidBlendMode())
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/CanvasUtils.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/CanvasUtils.android.kt
index 0b885ea..3f3d9ac 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/CanvasUtils.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/CanvasUtils.android.kt
@@ -19,6 +19,8 @@
import android.annotation.SuppressLint
import android.graphics.Canvas
import android.os.Build
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
@@ -35,11 +37,7 @@
@SuppressLint("SoonBlockedPrivateApi")
fun enableZ(canvas: Canvas, enable: Boolean) {
if (Build.VERSION.SDK_INT >= 29) {
- if (enable) {
- canvas.enableZ()
- } else {
- canvas.disableZ()
- }
+ CanvasZHelper.enableZ(canvas, enable)
} else {
if (!orderMethodsFetched) {
try {
@@ -89,3 +87,15 @@
}
}
}
+
+@RequiresApi(29)
+private object CanvasZHelper {
+ @DoNotInline
+ fun enableZ(canvas: Canvas, enable: Boolean) {
+ if (enable) {
+ canvas.enableZ()
+ } else {
+ canvas.disableZ()
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
index 6580236..6065fd0 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
@@ -74,6 +74,7 @@
import androidx.compose.ui.tooling.data.position
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
@@ -747,6 +748,33 @@
assertThat(first.packageHash).isEqualTo(hash)
}
+ @Composable
+ fun InlineParameters(size: Dp, fontSize: TextUnit) {
+ Text("$size $fontSize")
+ }
+
+ @Test
+ fun testInlineParameterTypes() {
+ val slotTableRecord = CompositionDataRecord.create()
+
+ show {
+ Inspectable(slotTableRecord) {
+ InlineParameters(20.5.dp, 30.sp)
+ }
+ }
+ val androidComposeView = findAndroidComposeView()
+ androidComposeView.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
+ val builder = LayoutInspectorTree()
+ builder.hideSystemNodes = false
+ val inlineParameters = builder.convert(androidComposeView)
+ .flatMap { flatten(it) }
+ .first { it.name == "InlineParameters" }
+ assertThat(inlineParameters.parameters[0].name).isEqualTo("size")
+ assertThat(inlineParameters.parameters[0].value?.javaClass).isEqualTo(Dp::class.java)
+ assertThat(inlineParameters.parameters[1].name).isEqualTo("fontSize")
+ assertThat(inlineParameters.parameters[1].value?.javaClass).isEqualTo(TextUnit::class.java)
+ }
+
@Suppress("SameParameterValue")
private fun validate(
result: List<InspectorNode>,
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt
index c335f85..91087fb 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt
@@ -959,7 +959,7 @@
maxRecursions: Int,
maxInitialIterableSize: Int
) {
- factory.clearCacheFor(ROOT_ID)
+ factory.clearReferenceCache()
val reference = NodeParameterReference(NODE_ID, ParameterKind.Normal, PARAM_INDEX, indices)
val expanded = expand(
name,
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
index d9c435d..3a917f6 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
@@ -17,6 +17,7 @@
package androidx.compose.ui.inspection.inspector
import android.view.View
+import androidx.annotation.RequiresApi
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.runtime.tooling.CompositionData
@@ -75,6 +76,7 @@
"ProvideCommonCompositionLocals",
)
+@OptIn(ExperimentalStdlibApi::class)
@VisibleForTesting
fun packageNameHash(packageName: String) =
packageName.fold(0) { hash, char -> hash * 31 + char.code }.absoluteValue
@@ -82,6 +84,7 @@
/**
* Generator of a tree for the Layout Inspector.
*/
+@RequiresApi(29)
class LayoutInspectorTree {
@Suppress("MemberVisibilityCanBePrivate")
var hideSystemNodes = true
@@ -202,6 +205,7 @@
@Suppress("unused")
fun resetAccumulativeState() {
subCompositions.resetAccumulativeState()
+ parameterFactory.clearReferenceCache()
// Reset the generated id. Nodes are assigned an id if there isn't a layout node id present.
generatedId = -1L
}
@@ -547,10 +551,13 @@
@OptIn(UiToolingDataApi::class)
private fun castValue(parameter: ParameterInformation): Any? {
val value = parameter.value ?: return null
- if (parameter.inlineClass == null || !value.javaClass.isPrimitive) return value
+ if (parameter.inlineClass == null || !isPrimitive(value.javaClass)) return value
return inlineClassConverter.castParameterValue(parameter.inlineClass, value)
}
+ private fun isPrimitive(cls: Class<*>): Boolean =
+ cls.kotlin.javaPrimitiveType != null
+
private fun unwantedGroup(node: MutableInspectorNode): Boolean =
(node.packageHash in systemPackages && hideSystemNodes) ||
node.name.isEmpty() ||
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt
index 20af4db..9d4b77f 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt
@@ -18,6 +18,7 @@
import android.util.Log
import android.view.View
+import androidx.annotation.RequiresApi
import androidx.compose.runtime.internal.ComposableLambda
import androidx.compose.ui.AbsoluteAlignment
import androidx.compose.ui.Modifier
@@ -64,6 +65,7 @@
*
* Each parameter value is converted to a user readable value.
*/
+@RequiresApi(29)
internal class ParameterFactory(private val inlineClassConverter: InlineClassConverter) {
/**
* A map from known values to a user readable string representation.
@@ -190,9 +192,9 @@
}
}
- fun clearCacheFor(rootId: Long) {
+ fun clearReferenceCache() {
val creator = creatorCache ?: return
- creator.clearCacheFor(rootId)
+ creator.clearReferenceCache()
}
private fun loadConstantsFrom(javaClass: Class<*>) {
@@ -382,8 +384,8 @@
return parameter
}
- fun clearCacheFor(rootId: Long) {
- rootValueIndexCache.remove(rootId)
+ fun clearReferenceCache() {
+ rootValueIndexCache.clear()
}
private fun setup(
diff --git a/compose/ui/ui-test/lint-baseline.xml b/compose/ui/ui-test/lint-baseline.xml
deleted file mode 100644
index 6021987..0000000
--- a/compose/ui/ui-test/lint-baseline.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-alpha01" type="baseline" client="cli" name="Lint" variant="all" version="7.1.0-alpha01">
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.ui.test.android.WindowCapture_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" decorView.viewTreeObserver.registerFrameCommitCallback {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/test/android/WindowCapture.android.kt"
- line="64"
- column="40"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.compose.ui.test.android.WindowCapture_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" PixelCopy.request(windowToCapture, captureRectInWindow, destBitmap, onCopyFinished, handler)"
- errorLine2=" ~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/test/android/WindowCapture.android.kt"
- line="100"
- column="15"/>
- </issue>
-
-</issues>
diff --git a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/android/WindowCapture.android.kt b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/android/WindowCapture.android.kt
index 85a3ab5..1946548 100644
--- a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/android/WindowCapture.android.kt
+++ b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/android/WindowCapture.android.kt
@@ -28,6 +28,7 @@
import android.view.View
import android.view.ViewTreeObserver
import android.view.Window
+import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
@@ -60,8 +61,8 @@
var drawDone = false
val decorView = windowToCapture.decorView
handler.post {
- if (Build.VERSION.SDK_INT >= 29 && decorView.isHardwareAccelerated()) {
- decorView.viewTreeObserver.registerFrameCommitCallback {
+ if (Build.VERSION.SDK_INT >= 29 && decorView.isHardwareAccelerated) {
+ FrameCommitCallbackHelper.registerFrameCommitCallback(decorView.viewTreeObserver) {
drawDone = true
}
} else {
@@ -97,7 +98,13 @@
copyResult = result
latch.countDown()
}
- PixelCopy.request(windowToCapture, captureRectInWindow, destBitmap, onCopyFinished, handler)
+ PixelCopyHelper.request(
+ windowToCapture,
+ captureRectInWindow,
+ destBitmap,
+ onCopyFinished,
+ handler
+ )
if (!latch.await(1, TimeUnit.SECONDS)) {
throw AssertionError("Failed waiting for PixelCopy!")
@@ -124,4 +131,26 @@
)
}
}
-}
\ No newline at end of file
+}
+
+@RequiresApi(29)
+private object FrameCommitCallbackHelper {
+ @DoNotInline
+ fun registerFrameCommitCallback(viewTreeObserver: ViewTreeObserver, runnable: Runnable) {
+ viewTreeObserver.registerFrameCommitCallback(runnable)
+ }
+}
+
+@RequiresApi(Build.VERSION_CODES.O)
+private object PixelCopyHelper {
+ @DoNotInline
+ fun request(
+ source: Window,
+ srcRect: Rect?,
+ dest: Bitmap,
+ listener: PixelCopy.OnPixelCopyFinishedListener,
+ listenerThread: Handler
+ ) {
+ PixelCopy.request(source, srcRect, dest, listener, listenerThread)
+ }
+}
diff --git a/compose/ui/ui-tooling/lint-baseline.xml b/compose/ui/ui-tooling/lint-baseline.xml
index f445f79..5f2bf52 100644
--- a/compose/ui/ui-tooling/lint-baseline.xml
+++ b/compose/ui/ui-tooling/lint-baseline.xml
@@ -23,15 +23,4 @@
column="30"/>
</issue>
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.compose.ui.tooling.preview.LayoutlibFontResourceLoader is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" is ResourceFont -> context.resources.getFont(font.resId)"
- errorLine2=" ~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/tooling/preview/LayoutlibFontResourceLoader.kt"
- line="33"
- column="50"/>
- </issue>
-
</issues>
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/LayoutlibFontResourceLoader.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/LayoutlibFontResourceLoader.kt
index 662a422..0c85551 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/LayoutlibFontResourceLoader.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/preview/LayoutlibFontResourceLoader.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.graphics.Typeface
import android.os.Build
+import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.ResourceFont
@@ -27,11 +28,19 @@
* Layoutlib implementation for [Font.ResourceLoader]
*/
internal class LayoutlibFontResourceLoader(private val context: Context) : Font.ResourceLoader {
- @RequiresApi(Build.VERSION_CODES.O)
override fun load(font: Font): Typeface {
- return when (font) {
- is ResourceFont -> context.resources.getFont(font.resId)
- else -> throw IllegalArgumentException("Unknown font type: ${font.javaClass.name}")
+ return if (font is ResourceFont && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ ResourceFontHelper.load(context, font)
+ } else {
+ throw IllegalArgumentException("Unknown font type: ${font.javaClass.name}")
}
}
}
+
+@RequiresApi(Build.VERSION_CODES.O)
+private object ResourceFontHelper {
+ @DoNotInline
+ fun load(context: Context, font: ResourceFont): Typeface {
+ return context.resources.getFont(font.resId)
+ }
+}
diff --git a/compose/ui/ui/api/1.0.0-beta09.txt b/compose/ui/ui/api/1.0.0-beta09.txt
index bb0a58a..09a5d1e 100644
--- a/compose/ui/ui/api/1.0.0-beta09.txt
+++ b/compose/ui/ui/api/1.0.0-beta09.txt
@@ -150,9 +150,6 @@
package androidx.compose.ui.autofill {
- public final class AndroidAutofillDebugUtils_androidKt {
- }
-
public final class AndroidAutofillType_androidKt {
}
diff --git a/compose/ui/ui/api/current.ignore b/compose/ui/ui/api/current.ignore
index 72e6f85..91311ea 100644
--- a/compose/ui/ui/api/current.ignore
+++ b/compose/ui/ui/api/current.ignore
@@ -27,6 +27,8 @@
Attempted to change parameter name from p to value in method androidx.compose.ui.layout.Placeable.setMeasurementConstraints-BRTryo0
+RemovedClass: androidx.compose.ui.autofill.AndroidAutofillDebugUtils_androidKt:
+ Removed class androidx.compose.ui.autofill.AndroidAutofillDebugUtils_androidKt
RemovedClass: androidx.compose.ui.input.pointer.RequestDisallowInterceptTouchEvent:
Removed class androidx.compose.ui.input.pointer.RequestDisallowInterceptTouchEvent
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index bb0a58a..09a5d1e 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -150,9 +150,6 @@
package androidx.compose.ui.autofill {
- public final class AndroidAutofillDebugUtils_androidKt {
- }
-
public final class AndroidAutofillType_androidKt {
}
diff --git a/compose/ui/ui/api/public_plus_experimental_1.0.0-beta09.txt b/compose/ui/ui/api/public_plus_experimental_1.0.0-beta09.txt
index 035b992..978818d 100644
--- a/compose/ui/ui/api/public_plus_experimental_1.0.0-beta09.txt
+++ b/compose/ui/ui/api/public_plus_experimental_1.0.0-beta09.txt
@@ -156,9 +156,6 @@
package androidx.compose.ui.autofill {
- public final class AndroidAutofillDebugUtils_androidKt {
- }
-
public final class AndroidAutofillType_androidKt {
}
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index 035b992..978818d 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -156,9 +156,6 @@
package androidx.compose.ui.autofill {
- public final class AndroidAutofillDebugUtils_androidKt {
- }
-
public final class AndroidAutofillType_androidKt {
}
diff --git a/compose/ui/ui/api/restricted_1.0.0-beta09.txt b/compose/ui/ui/api/restricted_1.0.0-beta09.txt
index f0d7adf..e772142 100644
--- a/compose/ui/ui/api/restricted_1.0.0-beta09.txt
+++ b/compose/ui/ui/api/restricted_1.0.0-beta09.txt
@@ -150,9 +150,6 @@
package androidx.compose.ui.autofill {
- public final class AndroidAutofillDebugUtils_androidKt {
- }
-
public final class AndroidAutofillType_androidKt {
}
diff --git a/compose/ui/ui/api/restricted_current.ignore b/compose/ui/ui/api/restricted_current.ignore
index 72e6f85..91311ea 100644
--- a/compose/ui/ui/api/restricted_current.ignore
+++ b/compose/ui/ui/api/restricted_current.ignore
@@ -27,6 +27,8 @@
Attempted to change parameter name from p to value in method androidx.compose.ui.layout.Placeable.setMeasurementConstraints-BRTryo0
+RemovedClass: androidx.compose.ui.autofill.AndroidAutofillDebugUtils_androidKt:
+ Removed class androidx.compose.ui.autofill.AndroidAutofillDebugUtils_androidKt
RemovedClass: androidx.compose.ui.input.pointer.RequestDisallowInterceptTouchEvent:
Removed class androidx.compose.ui.input.pointer.RequestDisallowInterceptTouchEvent
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index f0d7adf..e772142 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -150,9 +150,6 @@
package androidx.compose.ui.autofill {
- public final class AndroidAutofillDebugUtils_androidKt {
- }
-
public final class AndroidAutofillType_androidKt {
}
diff --git a/compose/ui/ui/lint-baseline.xml b/compose/ui/ui/lint-baseline.xml
index 56574e2..62a8a2f 100644
--- a/compose/ui/ui/lint-baseline.xml
+++ b/compose/ui/ui/lint-baseline.xml
@@ -22,60 +22,4 @@
line="341"
column="17"/>
</issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.compose.ui.autofill.AndroidAutofillDebugUtils_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" autofillManager.registerCallback(AutofillCallback)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillDebugUtils.android.kt"
- line="67"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 26; however, the containing class androidx.compose.ui.autofill.AndroidAutofillDebugUtils_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" autofillManager.unregisterCallback(AutofillCallback)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillDebugUtils.android.kt"
- line="77"
- column="21"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 23; however, the containing class androidx.compose.ui.res.ColorResources_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" Color(context.resources.getColor(id, context.theme))"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/res/ColorResources.android.kt"
- line="37"
- column="33"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.ui.input.pointer.MotionEventAdapter_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Offset(getRawX(index), getRawY(index))"
- errorLine2=" ~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt"
- line="194"
- column="19"/>
- </issue>
-
- <issue
- id="ClassVerificationFailure"
- message="This call references a method added in API level 29; however, the containing class androidx.compose.ui.input.pointer.MotionEventAdapter_androidKt is reachable from earlier API levels and will fail run-time class verification."
- errorLine1=" return Offset(getRawX(index), getRawY(index))"
- errorLine2=" ~~~~~~~">
- <location
- file="src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt"
- line="194"
- column="35"/>
- </issue>
-
</issues>
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillDebugUtils.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AutofillCallback.android.kt
similarity index 80%
rename from compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillDebugUtils.android.kt
rename to compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AutofillCallback.android.kt
index 79ada4f..a7b4d15 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofillDebugUtils.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AutofillCallback.android.kt
@@ -31,7 +31,7 @@
* for debug purposes.
*/
@RequiresApi(Build.VERSION_CODES.O)
-private object AutofillCallback : AutofillManager.AutofillCallback() {
+internal object AutofillCallback : AutofillManager.AutofillCallback() {
override fun onAutofillEvent(view: View, virtualId: Int, event: Int) {
super.onAutofillEvent(view, virtualId, event)
Log.d(
@@ -55,24 +55,22 @@
}
)
}
-}
-/**
- * Registers the autofill debug callback.
- */
-@ExperimentalComposeUiApi
-@RequiresApi(Build.VERSION_CODES.O)
-@DoNotInline
-internal fun AndroidAutofill.registerCallback() {
- autofillManager.registerCallback(AutofillCallback)
-}
+ /**
+ * Registers the autofill debug callback.
+ */
+ @ExperimentalComposeUiApi
+ @DoNotInline
+ fun register(autofill: AndroidAutofill) {
+ autofill.autofillManager.registerCallback(this)
+ }
-/**
- * Unregisters the autofill debug callback.
- */
-@ExperimentalComposeUiApi
-@RequiresApi(Build.VERSION_CODES.O)
-@DoNotInline
-internal fun AndroidAutofill.unregisterCallback() {
- autofillManager.unregisterCallback(AutofillCallback)
+ /**
+ * Unregisters the autofill debug callback.
+ */
+ @ExperimentalComposeUiApi
+ @DoNotInline
+ fun unregister(autofill: AndroidAutofill) {
+ autofill.autofillManager.unregisterCallback(this)
+ }
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt
index 7ebf120..d864a9f 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt
@@ -16,7 +16,6 @@
package androidx.compose.ui.input.pointer
-import android.annotation.SuppressLint
import android.os.Build
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_CANCEL
@@ -158,7 +157,7 @@
rawPosition = Offset(motionEvent.rawX, motionEvent.rawY)
position = positionCalculator.screenToLocal(rawPosition)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- rawPosition = motionEvent.toRawOffset(index)
+ rawPosition = MotionEventHelper.toRawOffset(motionEvent, index)
position = positionCalculator.screenToLocal(rawPosition)
} else {
rawPosition = positionCalculator.localToScreen(position)
@@ -188,8 +187,9 @@
* which use this method will pass.
*/
@RequiresApi(Build.VERSION_CODES.Q)
-@DoNotInline
-@SuppressLint("UnsafeNewApiCall") // not sure why RequiresApi is not enough
-private fun MotionEvent.toRawOffset(index: Int): Offset {
- return Offset(getRawX(index), getRawY(index))
+private object MotionEventHelper {
+ @DoNotInline
+ fun toRawOffset(motionEvent: MotionEvent, index: Int): Offset {
+ return Offset(motionEvent.getRawX(index), motionEvent.getRawY(index))
+ }
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
index e83a616..f533f76 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.android.kt
@@ -44,11 +44,10 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.autofill.AndroidAutofill
import androidx.compose.ui.autofill.Autofill
+import androidx.compose.ui.autofill.AutofillCallback
import androidx.compose.ui.autofill.AutofillTree
import androidx.compose.ui.autofill.performAutofill
import androidx.compose.ui.autofill.populateViewStructure
-import androidx.compose.ui.autofill.registerCallback
-import androidx.compose.ui.autofill.unregisterCallback
import androidx.compose.ui.focus.FOCUS_TAG
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.FocusDirection.Companion.Down
@@ -770,7 +769,11 @@
invalidateLayoutNodeMeasurement(root)
invalidateLayers(root)
snapshotObserver.startObserving()
- ifDebug { if (autofillSupported()) _autofill?.registerCallback() }
+ ifDebug {
+ if (autofillSupported()) {
+ _autofill?.let { AutofillCallback.register(it) }
+ }
+ }
val lifecycleOwner = ViewTreeLifecycleOwner.get(this)
val savedStateRegistryOwner = ViewTreeSavedStateRegistryOwner.get(this)
@@ -817,7 +820,11 @@
super.onDetachedFromWindow()
snapshotObserver.stopObserving()
viewTreeOwners?.lifecycleOwner?.lifecycle?.removeObserver(this)
- ifDebug { if (autofillSupported()) _autofill?.unregisterCallback() }
+ ifDebug {
+ if (autofillSupported()) {
+ _autofill?.let { AutofillCallback.unregister(it) }
+ }
+ }
viewTreeObserver.removeOnGlobalLayoutListener(globalLayoutListener)
viewTreeObserver.removeOnScrollChangedListener(scrollChangedListener)
}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/ColorResources.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/ColorResources.android.kt
index d56ac0c..257c8b5 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/ColorResources.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/res/ColorResources.android.kt
@@ -16,8 +16,11 @@
package androidx.compose.ui.res
+import android.content.Context
import android.os.Build
import androidx.annotation.ColorRes
+import androidx.annotation.DoNotInline
+import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.graphics.Color
@@ -34,9 +37,17 @@
fun colorResource(@ColorRes id: Int): Color {
val context = LocalContext.current
return if (Build.VERSION.SDK_INT >= 23) {
- Color(context.resources.getColor(id, context.theme))
+ ColorResourceHelper.getColor(context, id)
} else {
@Suppress("DEPRECATION")
Color(context.resources.getColor(id))
}
-}
\ No newline at end of file
+}
+
+@RequiresApi(23)
+private object ColorResourceHelper {
+ @DoNotInline
+ fun getColor(context: Context, @ColorRes id: Int): Color {
+ return Color(context.resources.getColor(id, context.theme))
+ }
+}
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
index b37b3e1..b7ec8da5 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidViewHolder.android.kt
@@ -205,11 +205,6 @@
return true
}
- override fun requestTransparentRegion(child: View?) {
- // We are not going to respect children's attempts for using transparent regions.
- // See gatherTransparentRegion.
- }
-
/**
* A [LayoutNode] tree representation for this Android [View] holder.
* The [LayoutNode] will proxy the Compose core calls to the [View].
diff --git a/core/core/api/api_lint.ignore b/core/core/api/api_lint.ignore
index d5ab240..b122d38 100644
--- a/core/core/api/api_lint.ignore
+++ b/core/core/api/api_lint.ignore
@@ -495,12 +495,6 @@
Missing nullability on parameter `sortOrder` in method `query`
MissingNullability: androidx.core.content.ContentResolverCompat#query(android.content.ContentResolver, android.net.Uri, String[], String, String[], String, androidx.core.os.CancellationSignal) parameter #6:
Missing nullability on parameter `cancellationSignal` in method `query`
-MissingNullability: androidx.core.content.ContextCompat#getCodeCacheDir(android.content.Context):
- Missing nullability on method `getCodeCacheDir` return
-MissingNullability: androidx.core.content.ContextCompat#getMainExecutor(android.content.Context):
- Missing nullability on method `getMainExecutor` return
-MissingNullability: androidx.core.content.ContextCompat#getMainExecutor(android.content.Context) parameter #0:
- Missing nullability on parameter `context` in method `getMainExecutor`
MissingNullability: androidx.core.content.FileProvider#getType(android.net.Uri):
Missing nullability on method `getType` return
MissingNullability: androidx.core.content.FileProvider#getUriForFile(android.content.Context, String, java.io.File):
@@ -1401,12 +1395,6 @@
Missing nullability on method `create` return
MissingNullability: androidx.core.view.animation.PathInterpolatorCompat#create(float, float, float, float):
Missing nullability on method `create` return
-MissingNullability: androidx.core.view.inputmethod.EditorInfoCompat#getContentMimeTypes(android.view.inputmethod.EditorInfo) parameter #0:
- Missing nullability on parameter `editorInfo` in method `getContentMimeTypes`
-MissingNullability: androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener#onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle) parameter #0:
- Missing nullability on parameter `inputContentInfo` in method `onCommitContent`
-MissingNullability: androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener#onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle) parameter #2:
- Missing nullability on parameter `opts` in method `onCommitContent`
MissingNullability: androidx.core.widget.AutoScrollHelper#onTouch(android.view.View, android.view.MotionEvent) parameter #0:
Missing nullability on parameter `v` in method `onTouch`
MissingNullability: androidx.core.widget.AutoScrollHelper#onTouch(android.view.View, android.view.MotionEvent) parameter #1:
@@ -1525,6 +1513,8 @@
Return type of method androidx.core.view.ViewCompat.getOnReceiveContentMimeTypes(android.view.View) is a nullable collection (`java.lang.String[]`); must be non-null
NullableCollection: androidx.core.view.accessibility.AccessibilityNodeProviderCompat#findAccessibilityNodeInfosByText(String, int):
Return type of method androidx.core.view.accessibility.AccessibilityNodeProviderCompat.findAccessibilityNodeInfosByText(String,int) is a nullable collection (`java.util.List`); must be non-null
+NullableCollection: androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener#onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle) parameter #2:
+ Type of parameter opts in androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener.onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat inputContentInfo, int flags, android.os.Bundle opts) is a nullable collection (`android.os.Bundle`); must be non-null
OptionalBuilderConstructorArgument: androidx.core.app.NotificationCompat.Action.Builder#Builder(androidx.core.graphics.drawable.IconCompat, CharSequence, android.app.PendingIntent) parameter #0:
@@ -1585,7 +1575,3 @@
Internal locks must not be exposed (synchronizing on this or class is still externally observable): method androidx.core.os.CancellationSignal.isCanceled()
VisiblySynchronized: androidx.core.os.CancellationSignal#setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener):
Internal locks must not be exposed (synchronizing on this or class is still externally observable): method androidx.core.os.CancellationSignal.setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener)
-VisiblySynchronized: androidx.core.widget.ContentLoadingProgressBar#hide():
- Internal locks must not be exposed: method androidx.core.widget.ContentLoadingProgressBar.hide()
-VisiblySynchronized: androidx.core.widget.ContentLoadingProgressBar#show():
- Internal locks must not be exposed: method androidx.core.widget.ContentLoadingProgressBar.show()
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index c1684a5..6f6ac82 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -956,14 +956,14 @@
method public static int checkSelfPermission(android.content.Context, String);
method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
method public static String? getAttributionTag(android.content.Context);
- method public static java.io.File! getCodeCacheDir(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
method public static java.io.File? getDataDir(android.content.Context);
method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
method public static java.io.File![] getExternalCacheDirs(android.content.Context);
method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
- method public static java.util.concurrent.Executor! getMainExecutor(android.content.Context!);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
method public static java.io.File? getNoBackupFilesDir(android.content.Context);
method public static java.io.File![] getObbDirs(android.content.Context);
method public static <T> T? getSystemService(android.content.Context, Class<T!>);
@@ -3292,7 +3292,7 @@
public final class EditorInfoCompat {
ctor @Deprecated public EditorInfoCompat();
- method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo!);
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
@@ -3311,7 +3311,7 @@
}
public static interface InputConnectionCompat.OnCommitContentListener {
- method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat!, int, android.os.Bundle!);
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
}
public final class InputContentInfoCompat {
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index 194c07e..c70a4319 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -956,14 +956,14 @@
method public static int checkSelfPermission(android.content.Context, String);
method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
method public static String? getAttributionTag(android.content.Context);
- method public static java.io.File! getCodeCacheDir(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
method public static java.io.File? getDataDir(android.content.Context);
method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
method public static java.io.File![] getExternalCacheDirs(android.content.Context);
method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
- method public static java.util.concurrent.Executor! getMainExecutor(android.content.Context!);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
method public static java.io.File? getNoBackupFilesDir(android.content.Context);
method public static java.io.File![] getObbDirs(android.content.Context);
method public static <T> T? getSystemService(android.content.Context, Class<T!>);
@@ -3296,7 +3296,7 @@
public final class EditorInfoCompat {
ctor @Deprecated public EditorInfoCompat();
- method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo!);
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
@@ -3315,7 +3315,7 @@
}
public static interface InputConnectionCompat.OnCommitContentListener {
- method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat!, int, android.os.Bundle!);
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
}
public final class InputContentInfoCompat {
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index d139d9f..8b57a96 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -1059,14 +1059,14 @@
method public static int checkSelfPermission(android.content.Context, String);
method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
method public static String? getAttributionTag(android.content.Context);
- method public static java.io.File! getCodeCacheDir(android.content.Context);
+ method public static java.io.File getCodeCacheDir(android.content.Context);
method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
method public static java.io.File? getDataDir(android.content.Context);
method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
method public static java.io.File![] getExternalCacheDirs(android.content.Context);
method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
- method public static java.util.concurrent.Executor! getMainExecutor(android.content.Context!);
+ method public static java.util.concurrent.Executor getMainExecutor(android.content.Context);
method public static java.io.File? getNoBackupFilesDir(android.content.Context);
method public static java.io.File![] getObbDirs(android.content.Context);
method public static <T> T? getSystemService(android.content.Context, Class<T!>);
@@ -3739,7 +3739,7 @@
public final class EditorInfoCompat {
ctor @Deprecated public EditorInfoCompat();
- method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo!);
+ method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo);
method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
@@ -3758,7 +3758,7 @@
}
public static interface InputConnectionCompat.OnCommitContentListener {
- method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat!, int, android.os.Bundle!);
+ method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
}
public final class InputContentInfoCompat {
diff --git a/core/core/lint-baseline.xml b/core/core/lint-baseline.xml
index 6943e8b..39e9183 100644
--- a/core/core/lint-baseline.xml
+++ b/core/core/lint-baseline.xml
@@ -10421,50 +10421,6 @@
<issue
id="PrivateConstructorForUtilityClass"
message="Utility class is missing private constructor"
- errorLine1="public class AppLaunchChecker {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/app/AppLaunchChecker.java"
- line="36"
- column="14"/>
- </issue>
-
- <issue
- id="PrivateConstructorForUtilityClass"
- message="Utility class is missing private constructor"
- errorLine1="public class ContextCompat {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/ContextCompat.java"
- line="156"
- column="14"/>
- </issue>
-
- <issue
- id="PrivateConstructorForUtilityClass"
- message="Utility class is missing private constructor"
- errorLine1="public final class EditorInfoCompat {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java"
- line="49"
- column="20"/>
- </issue>
-
- <issue
- id="PrivateConstructorForUtilityClass"
- message="Utility class is missing private constructor"
- errorLine1="public final class InputConnectionCompat {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java"
- line="37"
- column="20"/>
- </issue>
-
- <issue
- id="PrivateConstructorForUtilityClass"
- message="Utility class is missing private constructor"
errorLine1="public class NotificationCompat {"
errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
@@ -13244,39 +13200,6 @@
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" public static File getCodeCacheDir(@NonNull Context context) {"
- errorLine2=" ~~~~">
- <location
- file="src/main/java/androidx/core/content/ContextCompat.java"
- line="596"
- column="19"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" public static Executor getMainExecutor(Context context) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/ContextCompat.java"
- line="683"
- column="19"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" public static Executor getMainExecutor(Context context) {"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/core/content/ContextCompat.java"
- line="683"
- column="44"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
errorLine1=" Object getWrapper();"
errorLine2=" ~~~~~~">
<location
@@ -13552,17 +13475,6 @@
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" public static String[] getContentMimeTypes(EditorInfo editorInfo) {"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java"
- line="180"
- column="48"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
errorLine1=" public static Uri getUriForFile(@NonNull Context context, @NonNull String authority,"
errorLine2=" ~~~">
<location
@@ -14267,28 +14179,6 @@
<issue
id="UnknownNullness"
message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java"
- line="235"
- column="33"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
- errorLine1=" boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java"
- line="235"
- column="85"/>
- </issue>
-
- <issue
- id="UnknownNullness"
- message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
errorLine1=" public IBinder onBind(@NonNull Intent intent) {"
errorLine2=" ~~~~~~~">
<location
diff --git a/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java b/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java
index 60e2c56..e55d822 100644
--- a/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/content/ContextCompatTest.java
@@ -445,7 +445,7 @@
return ((size * tdensity) + (sdensity >> 1)) / sdensity;
}
- @Test(expected = IllegalArgumentException.class)
+ @Test(expected = NullPointerException.class)
public void testCheckSelfPermissionNull() {
ContextCompat.checkSelfPermission(mContext, null);
}
diff --git a/core/core/src/main/java/androidx/core/app/AppLaunchChecker.java b/core/core/src/main/java/androidx/core/app/AppLaunchChecker.java
index 8170aeb..65f8974 100644
--- a/core/core/src/main/java/androidx/core/app/AppLaunchChecker.java
+++ b/core/core/src/main/java/androidx/core/app/AppLaunchChecker.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-
package androidx.core.app;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -33,6 +33,8 @@
* than just if the app has been opened in the past in order to view a link,
* open a document or perform some other service for other apps on the device.
*/
+@SuppressWarnings("JavadocReference") // Unreliable warning
+@SuppressLint("PrivateConstructorForUtilityClass") // Already launched with public constructor
public class AppLaunchChecker {
private static final String SHARED_PREFS_NAME = "android.support.AppLaunchChecker";
private static final String KEY_STARTED_FROM_LAUNCHER = "startedFromLauncher";
@@ -83,7 +85,6 @@
/** @deprecated This type should not be instantiated as it contains only static methods. */
@Deprecated
- @SuppressWarnings("PrivateConstructorForUtilityClass")
public AppLaunchChecker() {
}
}
diff --git a/core/core/src/main/java/androidx/core/content/ContextCompat.java b/core/core/src/main/java/androidx/core/content/ContextCompat.java
index 2f54ab4..942112e 100644
--- a/core/core/src/main/java/androidx/core/content/ContextCompat.java
+++ b/core/core/src/main/java/androidx/core/content/ContextCompat.java
@@ -69,6 +69,7 @@
import static android.content.Context.WINDOW_SERVICE;
import android.accounts.AccountManager;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppOpsManager;
@@ -145,6 +146,7 @@
import androidx.core.content.res.ResourcesCompat;
import androidx.core.os.EnvironmentCompat;
import androidx.core.os.ExecutorCompat;
+import androidx.core.util.ObjectsCompat;
import java.io.File;
import java.util.HashMap;
@@ -153,6 +155,7 @@
/**
* Helper for accessing features in {@link Context}.
*/
+@SuppressLint("PrivateConstructorForUtilityClass") // Already launched with public constructor
public class ContextCompat {
private static final String TAG = "ContextCompat";
@@ -548,10 +551,7 @@
* @see PackageManager#checkPermission(String, String)
*/
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
- if (permission == null) {
- throw new IllegalArgumentException("permission is null");
- }
-
+ ObjectsCompat.requireNonNull(permission, "permission must be non-null");
return context.checkPermission(permission, Process.myPid(), Process.myUid());
}
@@ -593,6 +593,7 @@
*
* @return The path of the directory holding application code cache files.
*/
+ @NonNull
public static File getCodeCacheDir(@NonNull Context context) {
if (Build.VERSION.SDK_INT >= 21) {
return Api21Impl.getCodeCacheDir(context);
@@ -680,7 +681,8 @@
* thread associated with this context. This is the thread used to dispatch
* calls to application components (activities, services, etc).
*/
- public static Executor getMainExecutor(Context context) {
+ @NonNull
+ public static Executor getMainExecutor(@NonNull Context context) {
if (Build.VERSION.SDK_INT >= 28) {
return Api28Impl.getMainExecutor(context);
}
@@ -880,11 +882,6 @@
}
@DoNotInline
- static ColorStateList getColorStateList(Context obj, int id) {
- return obj.getColorStateList(id);
- }
-
- @DoNotInline
static int getColor(Context obj, int id) {
return obj.getColor(id);
}
@@ -928,6 +925,7 @@
// This class is not instantiable.
}
+ @SuppressWarnings("UnusedReturnValue")
@DoNotInline
static ComponentName startForegroundService(Context obj, Intent service) {
return obj.startForegroundService(service);
diff --git a/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java b/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java
index f454745..fedfc4b 100644
--- a/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/view/inputmethod/EditorInfoCompat.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,6 +26,7 @@
import static java.lang.annotation.RetentionPolicy.SOURCE;
+import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
@@ -46,6 +47,7 @@
/**
* Helper for accessing features in {@link EditorInfo} in a backwards compatible fashion.
*/
+@SuppressLint("PrivateConstructorForUtilityClass") // Already launched with public constructor
public final class EditorInfoCompat {
/**
@@ -177,7 +179,7 @@
* int, Bundle)} is not supported on this editor
*/
@NonNull
- public static String[] getContentMimeTypes(EditorInfo editorInfo) {
+ public static String[] getContentMimeTypes(@NonNull EditorInfo editorInfo) {
if (Build.VERSION.SDK_INT >= 25) {
final String[] result = editorInfo.contentMimeTypes;
return result != null ? result : EMPTY_STRING_ARRAY;
@@ -210,7 +212,7 @@
public static void setInitialSurroundingText(@NonNull EditorInfo editorInfo,
@NonNull CharSequence sourceText) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- Impl30.setInitialSurroundingSubText(editorInfo, sourceText, /* subTextStart= */ 0);
+ Api30Impl.setInitialSurroundingSubText(editorInfo, sourceText, /* subTextStart= */ 0);
} else {
setInitialSurroundingSubText(editorInfo, sourceText, /* subTextStart= */ 0);
}
@@ -234,7 +236,7 @@
@NonNull CharSequence subText, int subTextStart) {
Preconditions.checkNotNull(subText);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- Impl30.setInitialSurroundingSubText(editorInfo, subText, subTextStart);
+ Api30Impl.setInitialSurroundingSubText(editorInfo, subText, subTextStart);
return;
}
@@ -292,18 +294,17 @@
? 0 : sourceSelLength;
// Distribute rest of length quota to TextBeforeCursor and TextAfterCursor in 4:1 ratio.
- final int subTextBeforeCursorLength = selStart;
final int subTextAfterCursorLength = subText.length() - selEnd;
final int maxLengthMinusSelection = MEMORY_EFFICIENT_TEXT_LENGTH - newSelLength;
final int possibleMaxBeforeCursorLength =
- Math.min(subTextBeforeCursorLength, (int) (0.8 * maxLengthMinusSelection));
+ Math.min(selStart, (int) (0.8 * maxLengthMinusSelection));
int newAfterCursorLength = Math.min(subTextAfterCursorLength,
maxLengthMinusSelection - possibleMaxBeforeCursorLength);
- int newBeforeCursorLength = Math.min(subTextBeforeCursorLength,
+ int newBeforeCursorLength = Math.min(selStart,
maxLengthMinusSelection - newAfterCursorLength);
// As trimming may happen at the head of TextBeforeCursor, calculate new starting position.
- int newBeforeCursorHead = subTextBeforeCursorLength - newBeforeCursorLength;
+ int newBeforeCursorHead = selStart - newBeforeCursorLength;
// We don't want to cut surrogate pairs in the middle. Exam that at the new head and tail.
if (isCutOnSurrogate(subText,
@@ -354,7 +355,7 @@
public static CharSequence getInitialTextBeforeCursor(@NonNull EditorInfo editorInfo,
int length, int flags) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- return Impl30.getInitialTextBeforeCursor(editorInfo, length, flags);
+ return Api30Impl.getInitialTextBeforeCursor(editorInfo, length, flags);
}
if (editorInfo.extras == null) {
@@ -389,7 +390,7 @@
@Nullable
public static CharSequence getInitialSelectedText(@NonNull EditorInfo editorInfo, int flags) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- return Impl30.getInitialSelectedText(editorInfo, flags);
+ return Api30Impl.getInitialSelectedText(editorInfo, flags);
}
if (editorInfo.extras == null) {
@@ -397,10 +398,10 @@
}
// Swap selection start and end if necessary.
- final int correctedTextSelStart = editorInfo.initialSelStart > editorInfo.initialSelEnd
- ? editorInfo.initialSelEnd : editorInfo.initialSelStart;
- final int correctedTextSelEnd = editorInfo.initialSelStart > editorInfo.initialSelEnd
- ? editorInfo.initialSelStart : editorInfo.initialSelEnd;
+ final int correctedTextSelStart = Math.min(editorInfo.initialSelStart,
+ editorInfo.initialSelEnd);
+ final int correctedTextSelEnd = Math.max(editorInfo.initialSelStart,
+ editorInfo.initialSelEnd);
final int selectionHead = editorInfo.extras.getInt(CONTENT_SELECTION_HEAD_KEY);
final int selectionEnd = editorInfo.extras.getInt(CONTENT_SELECTION_END_KEY);
@@ -435,7 +436,7 @@
public static CharSequence getInitialTextAfterCursor(@NonNull EditorInfo editorInfo, int length,
int flags) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- return Impl30.getInitialTextAfterCursor(editorInfo, length, flags);
+ return Api30Impl.getInitialTextAfterCursor(editorInfo, length, flags);
}
if (editorInfo.extras == null) {
@@ -523,13 +524,12 @@
/** @deprecated This type should not be instantiated as it contains only static methods. */
@Deprecated
- @SuppressWarnings("PrivateConstructorForUtilityClass")
public EditorInfoCompat() {
}
@RequiresApi(30)
- private static class Impl30 {
- private Impl30() {}
+ private static class Api30Impl {
+ private Api30Impl() {}
static void setInitialSurroundingSubText(@NonNull EditorInfo editorInfo,
CharSequence sourceText, int subTextStart) {
diff --git a/core/core/src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java b/core/core/src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java
index 804c9d4..0ab64d2 100644
--- a/core/core/src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java
+++ b/core/core/src/main/java/androidx/core/view/inputmethod/InputConnectionCompat.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,7 @@
package androidx.core.view.inputmethod;
+import android.annotation.SuppressLint;
import android.content.ClipDescription;
import android.net.Uri;
import android.os.Build;
@@ -29,11 +30,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.util.ObjectsCompat;
/**
* Helper for accessing features in {@link InputConnection} introduced after API level 13 in a
* backwards compatible fashion.
*/
+@SuppressLint("PrivateConstructorForUtilityClass") // Already launched with public constructor
public final class InputConnectionCompat {
private static final String COMMIT_CONTENT_ACTION =
@@ -67,7 +70,7 @@
static boolean handlePerformPrivateCommand(
@Nullable String action,
- @NonNull Bundle data,
+ @Nullable Bundle data,
@NonNull OnCommitContentListener onCommitContentListener) {
if (data == null) {
return false;
@@ -232,7 +235,9 @@
* request is already handled or still being handled in background. {@code false} to use the
* default implementation
*/
- boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags, Bundle opts);
+ @SuppressWarnings("NullableProblems") // Not useful here
+ boolean onCommitContent(@NonNull InputContentInfoCompat inputContentInfo, int flags,
+ @Nullable Bundle opts);
}
/**
@@ -257,18 +262,15 @@
public static InputConnection createWrapper(@NonNull InputConnection inputConnection,
@NonNull EditorInfo editorInfo,
@NonNull OnCommitContentListener onCommitContentListener) {
- if (inputConnection == null) {
- throw new IllegalArgumentException("inputConnection must be non-null");
- }
- if (editorInfo == null) {
- throw new IllegalArgumentException("editorInfo must be non-null");
- }
- if (onCommitContentListener == null) {
- throw new IllegalArgumentException("onCommitContentListener must be non-null");
- }
+ ObjectsCompat.requireNonNull(inputConnection, "inputConnection must be non-null");
+ ObjectsCompat.requireNonNull(editorInfo, "editorInfo must be non-null");
+ ObjectsCompat.requireNonNull(onCommitContentListener,
+ "onCommitContentListener must be non-null");
+
if (Build.VERSION.SDK_INT >= 25) {
final OnCommitContentListener listener = onCommitContentListener;
return new InputConnectionWrapper(inputConnection, false /* mutable */) {
+ @SuppressWarnings("ConstantConditions") // Incorrect warning
@Override
public boolean commitContent(InputContentInfo inputContentInfo, int flags,
Bundle opts) {
@@ -299,7 +301,6 @@
/** @deprecated This type should not be instantiated as it contains only static methods. */
@Deprecated
- @SuppressWarnings("PrivateConstructorForUtilityClass")
public InputConnectionCompat() {
}
}
diff --git a/core/core/src/main/java/androidx/core/view/inputmethod/InputContentInfoCompat.java b/core/core/src/main/java/androidx/core/view/inputmethod/InputContentInfoCompat.java
index dc63be5..2f6a62a 100644
--- a/core/core/src/main/java/androidx/core/view/inputmethod/InputContentInfoCompat.java
+++ b/core/core/src/main/java/androidx/core/view/inputmethod/InputContentInfoCompat.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -91,12 +91,10 @@
@Override
public void requestPermission() {
- return;
}
@Override
public void releasePermission() {
- return;
}
}
@@ -134,7 +132,7 @@
}
@Override
- @Nullable
+ @NonNull
public Object getInputContentInfo() {
return mObject;
}
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index 68706f5..3b598ae 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -698,6 +698,7 @@
Extension: org\.jetbrains\.dokka\.base\.DokkaBase/fallbackMerger,
Extension: org\.jetbrains\.dokka\.base\.DokkaBase/docTagToContentConverter,
Extension: com\.google\.devsite\.DevsitePlugin/translator,
+Extension: com\.google\.devsite\.DevsitePlugin/hideFilter,
Extension: org\.jetbrains\.dokka\.base\.DokkaBase/extensionsExtractor,
Extension: org\.jetbrains\.dokka\.base\.DokkaBase/undocumentedCodeReporter,
Extension: org\.jetbrains\.dokka\.base\.DokkaBase/inheritorsExtractor,
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 28e9139..1a467b5 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -131,7 +131,7 @@
shadow = { module = "com.github.jengelman.gradle.plugins:shadow", version = "6.1.0" }
sqldelightAndroid = { module = "com.squareup.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelightCoroutinesExt = { module = "com.squareup.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
-sqliteJdbc = { module = "org.xerial:sqlite-jdbc", version = "3.25.2" }
+sqliteJdbc = { module = "org.xerial:sqlite-jdbc", version = "3.34.0" }
testCore = { module = "androidx.test:core", version.ref = "androidxTest" }
testExtJunit = { module = "androidx.test.ext:junit", version.ref = "androidxTestExt" }
testExtJunitKtx = { module = "androidx.test.ext:junit-ktx", version.ref = "androidxTestExt" }
diff --git a/profileinstaller/profileinstaller-benchmark/src/androidTest/java/androidx/profileinstaller/benchmark/ProfileInstallerTranscodeBenchmark.kt b/profileinstaller/profileinstaller-benchmark/src/androidTest/java/androidx/profileinstaller/benchmark/ProfileInstallerTranscodeBenchmark.kt
index 1812a8f..f415a66 100644
--- a/profileinstaller/profileinstaller-benchmark/src/androidTest/java/androidx/profileinstaller/benchmark/ProfileInstallerTranscodeBenchmark.kt
+++ b/profileinstaller/profileinstaller-benchmark/src/androidTest/java/androidx/profileinstaller/benchmark/ProfileInstallerTranscodeBenchmark.kt
@@ -59,6 +59,7 @@
runWithTimingDisabled {
transcoder = DeviceProfileWriter(
assets,
+ Runnable::run,
Diagnostics(),
PROFILE_LOCATION,
mTempCurFile!!,
@@ -71,6 +72,7 @@
private fun assumeDeviceSupportsAot() {
val transcoder = DeviceProfileWriter(
assets,
+ Runnable::run,
Diagnostics(),
PROFILE_LOCATION,
mTempCurFile!!,
@@ -86,6 +88,7 @@
fun deviceAllowsProfileInstallerAotWrites() {
val transcoder = DeviceProfileWriter(
assets,
+ Runnable::run,
Diagnostics(),
PROFILE_LOCATION,
mTempCurFile!!,
@@ -137,6 +140,7 @@
benchmarkRule.measureRepeated {
val transcoder = DeviceProfileWriter(
assets,
+ Runnable::run,
Diagnostics(),
PROFILE_LOCATION,
mTempCurFile!!,
@@ -154,12 +158,12 @@
const val PROFILE_LOCATION = "golden/profileinstaller.prof"
}
- class Diagnostics : ProfileInstaller.Diagnostics {
- override fun diagnostic(code: Int, data: Any?) {
+ class Diagnostics : ProfileInstaller.DiagnosticsCallback {
+ override fun onDiagnosticReceived(code: Int, data: Any?) {
/* no-op */
}
- override fun result(code: Int, data: Any?) {
+ override fun onResultReceived(code: Int, data: Any?) {
/* no-op */
}
}
diff --git a/profileinstaller/profileinstaller/api/current.txt b/profileinstaller/profileinstaller/api/current.txt
index 1f9d6d2..80c25f8 100644
--- a/profileinstaller/profileinstaller/api/current.txt
+++ b/profileinstaller/profileinstaller/api/current.txt
@@ -9,12 +9,11 @@
public class ProfileInstaller {
method @WorkerThread public static void writeProfile(android.content.Context);
- method @WorkerThread public static void writeProfile(android.content.Context, androidx.profileinstaller.ProfileInstaller.Diagnostics);
+ method @WorkerThread public static void writeProfile(android.content.Context, java.util.concurrent.Executor, androidx.profileinstaller.ProfileInstaller.DiagnosticsCallback);
field public static final int DIAGNOSTIC_CURRENT_PROFILE_DOES_NOT_EXIST = 2; // 0x2
field public static final int DIAGNOSTIC_CURRENT_PROFILE_EXISTS = 1; // 0x1
field public static final int DIAGNOSTIC_REF_PROFILE_DOES_NOT_EXIST = 4; // 0x4
field public static final int DIAGNOSTIC_REF_PROFILE_EXISTS = 3; // 0x3
- field public static final androidx.profileinstaller.ProfileInstaller.Diagnostics LOG_DIAGNOSTICS;
field public static final int RESULT_ALREADY_INSTALLED = 2; // 0x2
field public static final int RESULT_BASELINE_PROFILE_NOT_FOUND = 6; // 0x6
field public static final int RESULT_DESIRED_FORMAT_UNSUPPORTED = 5; // 0x5
@@ -25,9 +24,9 @@
field public static final int RESULT_UNSUPPORTED_ART_VERSION = 3; // 0x3
}
- public static interface ProfileInstaller.Diagnostics {
- method public void diagnostic(int, Object?);
- method public void result(int, Object?);
+ public static interface ProfileInstaller.DiagnosticsCallback {
+ method public void onDiagnosticReceived(int, Object?);
+ method public void onResultReceived(int, Object?);
}
public class ProfileInstallerInitializer implements androidx.startup.Initializer<androidx.profileinstaller.ProfileInstallerInitializer.Result> {
diff --git a/profileinstaller/profileinstaller/api/public_plus_experimental_current.txt b/profileinstaller/profileinstaller/api/public_plus_experimental_current.txt
index 1f9d6d2..80c25f8 100644
--- a/profileinstaller/profileinstaller/api/public_plus_experimental_current.txt
+++ b/profileinstaller/profileinstaller/api/public_plus_experimental_current.txt
@@ -9,12 +9,11 @@
public class ProfileInstaller {
method @WorkerThread public static void writeProfile(android.content.Context);
- method @WorkerThread public static void writeProfile(android.content.Context, androidx.profileinstaller.ProfileInstaller.Diagnostics);
+ method @WorkerThread public static void writeProfile(android.content.Context, java.util.concurrent.Executor, androidx.profileinstaller.ProfileInstaller.DiagnosticsCallback);
field public static final int DIAGNOSTIC_CURRENT_PROFILE_DOES_NOT_EXIST = 2; // 0x2
field public static final int DIAGNOSTIC_CURRENT_PROFILE_EXISTS = 1; // 0x1
field public static final int DIAGNOSTIC_REF_PROFILE_DOES_NOT_EXIST = 4; // 0x4
field public static final int DIAGNOSTIC_REF_PROFILE_EXISTS = 3; // 0x3
- field public static final androidx.profileinstaller.ProfileInstaller.Diagnostics LOG_DIAGNOSTICS;
field public static final int RESULT_ALREADY_INSTALLED = 2; // 0x2
field public static final int RESULT_BASELINE_PROFILE_NOT_FOUND = 6; // 0x6
field public static final int RESULT_DESIRED_FORMAT_UNSUPPORTED = 5; // 0x5
@@ -25,9 +24,9 @@
field public static final int RESULT_UNSUPPORTED_ART_VERSION = 3; // 0x3
}
- public static interface ProfileInstaller.Diagnostics {
- method public void diagnostic(int, Object?);
- method public void result(int, Object?);
+ public static interface ProfileInstaller.DiagnosticsCallback {
+ method public void onDiagnosticReceived(int, Object?);
+ method public void onResultReceived(int, Object?);
}
public class ProfileInstallerInitializer implements androidx.startup.Initializer<androidx.profileinstaller.ProfileInstallerInitializer.Result> {
diff --git a/profileinstaller/profileinstaller/api/restricted_current.txt b/profileinstaller/profileinstaller/api/restricted_current.txt
index 1f9d6d2..80c25f8 100644
--- a/profileinstaller/profileinstaller/api/restricted_current.txt
+++ b/profileinstaller/profileinstaller/api/restricted_current.txt
@@ -9,12 +9,11 @@
public class ProfileInstaller {
method @WorkerThread public static void writeProfile(android.content.Context);
- method @WorkerThread public static void writeProfile(android.content.Context, androidx.profileinstaller.ProfileInstaller.Diagnostics);
+ method @WorkerThread public static void writeProfile(android.content.Context, java.util.concurrent.Executor, androidx.profileinstaller.ProfileInstaller.DiagnosticsCallback);
field public static final int DIAGNOSTIC_CURRENT_PROFILE_DOES_NOT_EXIST = 2; // 0x2
field public static final int DIAGNOSTIC_CURRENT_PROFILE_EXISTS = 1; // 0x1
field public static final int DIAGNOSTIC_REF_PROFILE_DOES_NOT_EXIST = 4; // 0x4
field public static final int DIAGNOSTIC_REF_PROFILE_EXISTS = 3; // 0x3
- field public static final androidx.profileinstaller.ProfileInstaller.Diagnostics LOG_DIAGNOSTICS;
field public static final int RESULT_ALREADY_INSTALLED = 2; // 0x2
field public static final int RESULT_BASELINE_PROFILE_NOT_FOUND = 6; // 0x6
field public static final int RESULT_DESIRED_FORMAT_UNSUPPORTED = 5; // 0x5
@@ -25,9 +24,9 @@
field public static final int RESULT_UNSUPPORTED_ART_VERSION = 3; // 0x3
}
- public static interface ProfileInstaller.Diagnostics {
- method public void diagnostic(int, Object?);
- method public void result(int, Object?);
+ public static interface ProfileInstaller.DiagnosticsCallback {
+ method public void onDiagnosticReceived(int, Object?);
+ method public void onResultReceived(int, Object?);
}
public class ProfileInstallerInitializer implements androidx.startup.Initializer<androidx.profileinstaller.ProfileInstallerInitializer.Result> {
diff --git a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java
index 543983b..41bc835 100644
--- a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java
+++ b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/DeviceProfileWriter.java
@@ -35,6 +35,7 @@
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Map;
+import java.util.concurrent.Executor;
/**
* Orchestrate device-level profiler decisions.
@@ -62,7 +63,9 @@
@NonNull
private final AssetManager mAssetManager;
@NonNull
- private final ProfileInstaller.Diagnostics mDiagnostics;
+ private final Executor mExecutor;
+ @NonNull
+ private final ProfileInstaller.DiagnosticsCallback mDiagnostics;
@Nullable
private final byte[] mDesiredVersion;
@NonNull
@@ -77,16 +80,23 @@
@Nullable
private byte[] mTranscodedProfile;
+ private void result(@ProfileInstaller.ResultCode int code, @Nullable Object data) {
+ mExecutor.execute(() -> { mDiagnostics.onResultReceived(code, data); });
+ }
+
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public DeviceProfileWriter(@NonNull AssetManager assetManager,
- @NonNull ProfileInstaller.Diagnostics diagnostics,
- @NonNull String profileSourceLocation, @NonNull File curProfile,
+ @NonNull Executor executor,
+ @NonNull ProfileInstaller.DiagnosticsCallback diagnosticsCallback,
+ @NonNull String profileSourceLocation,
+ @NonNull File curProfile,
@NonNull File refProfile) {
mAssetManager = assetManager;
- mDiagnostics = diagnostics;
+ mExecutor = executor;
+ mDiagnostics = diagnosticsCallback;
mProfileSourceLocation = profileSourceLocation;
mCurProfile = curProfile;
mRefProfile = refProfile;
@@ -99,8 +109,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY)
public boolean deviceAllowsProfileInstallerAotWrites() {
if (mDesiredVersion == null) {
- mDiagnostics.result(ProfileInstaller.RESULT_UNSUPPORTED_ART_VERSION,
- Build.VERSION.SDK_INT);
+ result(ProfileInstaller.RESULT_UNSUPPORTED_ART_VERSION, Build.VERSION.SDK_INT);
return false;
}
@@ -108,7 +117,7 @@
// It's possible that some OEMs might not allow writing to this directory. If this is
// the case, there's not really anything we can do, so we should quit before doing
// any unnecessary work.
- mDiagnostics.result(ProfileInstaller.RESULT_NOT_WRITABLE, null);
+ result(ProfileInstaller.RESULT_NOT_WRITABLE, null);
return false;
}
@@ -167,16 +176,19 @@
ProfileTranscoder.writeHeader(os, desiredVersion);
Encoding.writeAll(is, os);
}
- mDiagnostics.result(ProfileInstaller.RESULT_INSTALL_SUCCESS, null);
+ mDiagnostics.onResultReceived(
+ ProfileInstaller.RESULT_INSTALL_SUCCESS,
+ null
+ );
}
}
}
} catch (FileNotFoundException e) {
- mDiagnostics.result(ProfileInstaller.RESULT_BASELINE_PROFILE_NOT_FOUND, e);
+ mDiagnostics.onResultReceived(ProfileInstaller.RESULT_BASELINE_PROFILE_NOT_FOUND, e);
} catch (IOException e) {
- mDiagnostics.result(ProfileInstaller.RESULT_IO_EXCEPTION, e);
+ mDiagnostics.onResultReceived(ProfileInstaller.RESULT_IO_EXCEPTION, e);
} catch (IllegalStateException e) {
- mDiagnostics.result(ProfileInstaller.RESULT_PARSE_EXCEPTION, e);
+ mDiagnostics.onResultReceived(ProfileInstaller.RESULT_PARSE_EXCEPTION, e);
}
return this;
}
@@ -216,16 +228,19 @@
);
if (!success) {
- mDiagnostics.result(ProfileInstaller.RESULT_DESIRED_FORMAT_UNSUPPORTED, null);
+ mDiagnostics.onResultReceived(
+ ProfileInstaller.RESULT_DESIRED_FORMAT_UNSUPPORTED,
+ null
+ );
mProfile = null;
return this;
}
mTranscodedProfile = os.toByteArray();
} catch (IOException e) {
- mDiagnostics.result(ProfileInstaller.RESULT_IO_EXCEPTION, e);
+ mDiagnostics.onResultReceived(ProfileInstaller.RESULT_IO_EXCEPTION, e);
} catch (IllegalStateException e) {
- mDiagnostics.result(ProfileInstaller.RESULT_PARSE_EXCEPTION, e);
+ mDiagnostics.onResultReceived(ProfileInstaller.RESULT_PARSE_EXCEPTION, e);
}
mProfile = null;
return this;
@@ -252,11 +267,11 @@
OutputStream os = new FileOutputStream(mCurProfile)
) {
Encoding.writeAll(bis, os);
- mDiagnostics.result(ProfileInstaller.RESULT_INSTALL_SUCCESS, null);
+ result(ProfileInstaller.RESULT_INSTALL_SUCCESS, null);
} catch (FileNotFoundException e) {
- mDiagnostics.result(ProfileInstaller.RESULT_BASELINE_PROFILE_NOT_FOUND, e);
+ result(ProfileInstaller.RESULT_BASELINE_PROFILE_NOT_FOUND, e);
} catch (IOException e) {
- mDiagnostics.result(ProfileInstaller.RESULT_IO_EXCEPTION, e);
+ result(ProfileInstaller.RESULT_IO_EXCEPTION, e);
} finally {
mTranscodedProfile = null;
mProfile = null;
diff --git a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstallReceiver.java b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstallReceiver.java
index aeeaf2e..43a28ad 100644
--- a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstallReceiver.java
+++ b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstallReceiver.java
@@ -43,18 +43,18 @@
public void onReceive(@NonNull Context context, @Nullable Intent intent) {
if (intent == null) return;
if (!ACTION_INSTALL_PROFILE.equals(intent.getAction())) return;
- ProfileInstaller.writeProfile(context, new ResultDiagnostics());
+ ProfileInstaller.writeProfile(context, Runnable::run, new ResultDiagnostics());
}
- class ResultDiagnostics implements ProfileInstaller.Diagnostics {
+ class ResultDiagnostics implements ProfileInstaller.DiagnosticsCallback {
@Override
- public void diagnostic(int code, @Nullable Object data) {
- ProfileInstaller.LOG_DIAGNOSTICS.diagnostic(code, data);
+ public void onDiagnosticReceived(int code, @Nullable Object data) {
+ ProfileInstaller.LOG_DIAGNOSTICS.onDiagnosticReceived(code, data);
}
@Override
- public void result(int code, @Nullable Object data) {
- ProfileInstaller.LOG_DIAGNOSTICS.result(code, data);
+ public void onResultReceived(int code, @Nullable Object data) {
+ ProfileInstaller.LOG_DIAGNOSTICS.onResultReceived(code, data);
setResultCode(code);
}
}
diff --git a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java
index b378f5c..349db88 100644
--- a/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java
+++ b/profileinstaller/profileinstaller/src/main/java/androidx/profileinstaller/ProfileInstaller.java
@@ -30,6 +30,7 @@
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
/**
* Install ahead of time tracing profiles to configure ART to precompile bundled libraries.
@@ -60,7 +61,7 @@
* An object which can be passed to the ProfileInstaller which will receive information
* during the installation process which can be used for logging and telemetry.
*/
- public interface Diagnostics {
+ public interface DiagnosticsCallback {
/**
* The diagnostic method will get called 0 to many times during the installation process,
* and is passed a [code] and optionally [data] which provides some information around
@@ -68,7 +69,7 @@
* @param code An int specifying which diagnostic situation has occurred.
* @param data Optional data passed in that relates to the code passed.
*/
- void diagnostic(@DiagnosticCode int code, @Nullable Object data);
+ void onDiagnosticReceived(@DiagnosticCode int code, @Nullable Object data);
/**
* The result method will get called exactly once per installation, with a [code]
@@ -77,27 +78,46 @@
* @param code An int specifying which result situation has occurred.
* @param data Optional data passed in that relates to the code that was passed.
*/
- void result(@ResultCode int code, @Nullable Object data);
+ void onResultReceived(@ResultCode int code, @Nullable Object data);
}
- private static final Diagnostics EMPTY_DIAGNOSTICS = new Diagnostics() {
+ @SuppressWarnings("SameParameterValue")
+ static void result(
+ @NonNull Executor executor,
+ @NonNull DiagnosticsCallback diagnostics,
+ @ResultCode int code,
+ @Nullable Object data
+ ) {
+ executor.execute(() -> diagnostics.onResultReceived(code, data));
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ static void diagnostic(
+ @NonNull Executor executor,
+ @NonNull DiagnosticsCallback diagnostics,
+ @DiagnosticCode int code,
+ @Nullable Object data
+ ) {
+ executor.execute(() -> diagnostics.onDiagnosticReceived(code, data));
+ }
+
+ private static final DiagnosticsCallback EMPTY_DIAGNOSTICS = new DiagnosticsCallback() {
@Override
- public void diagnostic(int code, @Nullable Object data) {
+ public void onDiagnosticReceived(int code, @Nullable Object data) {
// do nothing
}
@Override
- public void result(int code, @Nullable Object data) {
+ public void onResultReceived(int code, @Nullable Object data) {
// do nothing
}
};
- @SuppressWarnings("unused")
@NonNull
- public static final Diagnostics LOG_DIAGNOSTICS = new Diagnostics() {
+ static final DiagnosticsCallback LOG_DIAGNOSTICS = new DiagnosticsCallback() {
static final String TAG = "ProfileInstaller";
@Override
- public void diagnostic(int code, @Nullable Object data) {
+ public void onDiagnosticReceived(int code, @Nullable Object data) {
String msg = "";
switch (code) {
case DIAGNOSTIC_CURRENT_PROFILE_EXISTS:
@@ -117,7 +137,7 @@
}
@Override
- public void result(int code, @Nullable Object data) {
+ public void onResultReceived(int code, @Nullable Object data) {
String msg = "";
switch (code) {
case RESULT_INSTALL_SUCCESS: msg = "RESULT_INSTALL_SUCCESS";
@@ -258,7 +278,8 @@
@ResultCode public static final int RESULT_PARSE_EXCEPTION = 8;
static boolean shouldSkipInstall(
- @NonNull Diagnostics diagnostics,
+ @NonNull Executor executor,
+ @NonNull DiagnosticsCallback diagnostics,
long baselineLength,
boolean curExists,
long curLength,
@@ -267,22 +288,22 @@
) {
if (curExists && curLength > MIN_MEANINGFUL_LENGTH) {
// There's a non-empty profile sitting in this directory
- diagnostics.diagnostic(DIAGNOSTIC_CURRENT_PROFILE_EXISTS, null);
+ diagnostic(executor, diagnostics, DIAGNOSTIC_CURRENT_PROFILE_EXISTS, null);
} else {
- diagnostics.diagnostic(DIAGNOSTIC_CURRENT_PROFILE_DOES_NOT_EXIST, null);
+ diagnostic(executor, diagnostics, DIAGNOSTIC_CURRENT_PROFILE_DOES_NOT_EXIST, null);
}
if (refExists && refLength > MIN_MEANINGFUL_LENGTH) {
- diagnostics.diagnostic(DIAGNOSTIC_REF_PROFILE_EXISTS, null);
+ diagnostic(executor, diagnostics, DIAGNOSTIC_REF_PROFILE_EXISTS, null);
} else {
- diagnostics.diagnostic(DIAGNOSTIC_REF_PROFILE_DOES_NOT_EXIST, null);
+ diagnostic(executor, diagnostics, DIAGNOSTIC_REF_PROFILE_DOES_NOT_EXIST, null);
}
if (baselineLength > 0 && baselineLength == curLength) {
// If the profiles are exactly the same size, we make the assumption that
// they are in fact the same profile. In this case, there is no work for
// us to do and we can exit early.
- diagnostics.result(RESULT_ALREADY_INSTALLED, null);
+ result(executor, diagnostics, RESULT_ALREADY_INSTALLED, null);
return true;
}
@@ -290,7 +311,7 @@
// If the profiles are exactly the same size, we make the assumption that
// they are in fact the same profile. In this case, there is no work for
// us to do and we can exit early.
- diagnostics.result(RESULT_ALREADY_INSTALLED, null);
+ result(executor, diagnostics, RESULT_ALREADY_INSTALLED, null);
return true;
}
@@ -305,7 +326,7 @@
// TODO: we could do something a bit smarter here to indicate that we've
// already written the profile. For instance, we could save a file marking the
// install and look at that.
- diagnostics.result(RESULT_ALREADY_INSTALLED, null);
+ result(executor, diagnostics, RESULT_ALREADY_INSTALLED, null);
return true;
}
return false;
@@ -317,22 +338,28 @@
*
* @param assets the asset manager to read source file from dexopt/baseline.prof
* @param packageName package name of the current apk
- * @param diagnostics The diagnostics object to pass diagnostics to
+ * @param diagnostics The diagnostics callback to pass diagnostics to
*/
private static void transcodeAndWrite(
@NonNull AssetManager assets,
@NonNull String packageName,
- @NonNull Diagnostics diagnostics
+ @NonNull Executor executor,
+ @NonNull DiagnosticsCallback diagnostics
) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
- diagnostics.result(ProfileInstaller.RESULT_UNSUPPORTED_ART_VERSION, null);
+ result(executor, diagnostics, ProfileInstaller.RESULT_UNSUPPORTED_ART_VERSION, null);
return;
}
File curProfile = new File(new File(PROFILE_BASE_DIR, packageName), PROFILE_FILE);
File refProfile = new File(new File(PROFILE_REF_BASE_DIR, packageName), PROFILE_FILE);
- DeviceProfileWriter deviceProfileWriter = new DeviceProfileWriter(assets, diagnostics,
- PROFILE_SOURCE_LOCATION, curProfile, refProfile);
+ DeviceProfileWriter deviceProfileWriter = new DeviceProfileWriter(assets,
+ executor,
+ diagnostics,
+ PROFILE_SOURCE_LOCATION,
+ curProfile,
+ refProfile
+ );
if (!deviceProfileWriter.deviceAllowsProfileInstallerAotWrites()) {
return; /* nothing else to do here */
@@ -340,9 +367,14 @@
DeviceProfileWriter.SkipStrategy skipStrategy =
(newProfileLength, existingProfileState) -> shouldSkipInstall(
- diagnostics, newProfileLength,
- existingProfileState.hasCurFile(), existingProfileState.getCurLength(),
- existingProfileState.hasRefFile(), existingProfileState.getRefLength());
+ executor,
+ diagnostics,
+ newProfileLength,
+ existingProfileState.hasCurFile(),
+ existingProfileState.getCurLength(),
+ existingProfileState.hasRefFile(),
+ existingProfileState.getRefLength()
+ );
deviceProfileWriter.copyProfileOrRead(skipStrategy)
.transcodeIfNeeded()
@@ -374,7 +406,7 @@
*/
@WorkerThread
public static void writeProfile(@NonNull Context context) {
- writeProfile(context, EMPTY_DIAGNOSTICS);
+ writeProfile(context, Runnable::run, EMPTY_DIAGNOSTICS);
}
/**
@@ -400,13 +432,19 @@
*
* @param context context to read assets from
- * @param diagnostics an object which will receive diagnostic information about the installation
+ * @param diagnostics an object which will receive diagnostic information about the
+ * installation
+ * @param executor the executor to run the diagnostic events through
*/
@WorkerThread
- public static void writeProfile(@NonNull Context context, @NonNull Diagnostics diagnostics) {
+ public static void writeProfile(
+ @NonNull Context context,
+ @NonNull Executor executor,
+ @NonNull DiagnosticsCallback diagnostics
+ ) {
Context appContext = context.getApplicationContext();
String packageName = appContext.getPackageName();
AssetManager assetManager = appContext.getAssets();
- transcodeAndWrite(assetManager, packageName, diagnostics);
+ transcodeAndWrite(assetManager, packageName, executor, diagnostics);
}
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt b/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
index d7fd403..b435de1 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/verifier/DatabaseVerifier.kt
@@ -26,7 +26,6 @@
import androidx.room.vo.Warning
import columnInfo
import org.sqlite.JDBC
-import org.sqlite.SQLiteJDBCLoader
import java.io.File
import java.sql.Connection
import java.sql.SQLException
@@ -68,7 +67,7 @@
// multiple library versions, process isolation and multiple class loaders by using
// UUID named library files.
synchronized(System::class.java) {
- SQLiteJDBCLoader.initialize() // extract and loads native library
+ NativeSQLiteLoader.load() // extract and loads native library
JDBC.isValidURL(CONNECTION_URL) // call to register driver
}
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/verifier/NativeSQLiteLoader.kt b/room/room-compiler/src/main/kotlin/androidx/room/verifier/NativeSQLiteLoader.kt
new file mode 100644
index 0000000..677411c
--- /dev/null
+++ b/room/room-compiler/src/main/kotlin/androidx/room/verifier/NativeSQLiteLoader.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.verifier
+
+import org.sqlite.SQLiteJDBCLoader
+import org.sqlite.util.OSInfo
+import java.io.File
+import java.io.IOException
+import java.io.InputStream
+import java.util.UUID
+
+/**
+ * A custom sqlite-jdbc native library extractor and loader.
+ *
+ * This class is used instead of [SQLiteJDBCLoader.initialize] since it workarounds current issues
+ * in the loading strategy, specifically: https://github.com/xerial/sqlite-jdbc/pull/578.
+ */
+internal object NativeSQLiteLoader {
+
+ private var loaded = false
+
+ private val tempDir: File by lazy {
+ File(System.getProperty("org.sqlite.tmpdir", System.getProperty("java.io.tmpdir")))
+ }
+
+ private val version: String by lazy { SQLiteJDBCLoader.getVersion() }
+
+ @JvmStatic
+ fun load() = synchronized(loaded) {
+ if (loaded) return
+ try {
+ // Cleanup target temporary folder for a new extraction.
+ cleanupTempFolder()
+ // Extract and load native library.
+ loadNativeLibrary()
+ // Reflect into original loader and mark library as extracted.
+ SQLiteJDBCLoader::class.java.getDeclaredField("extracted")
+ .apply { trySetAccessible() }
+ .set(null, true)
+ } catch (ex: Exception) {
+ // Fallback to main library if our attempt failed, do print error juuust in case, so if
+ // there is an error with our approach we get to know, instead of fully swallowing it.
+ RuntimeException("Failed to load native SQLite library, will try again though.", ex)
+ .printStackTrace()
+ SQLiteJDBCLoader.initialize()
+ }
+ loaded = true
+ }
+
+ private fun cleanupTempFolder() {
+ tempDir.listFiles { file ->
+ file.name.startsWith("sqlite-$version") && !file.name.endsWith(".lck")
+ }?.forEach { libFile ->
+ val lckFile = File(libFile.absolutePath + ".lck")
+ if (!lckFile.exists()) {
+ libFile.delete()
+ }
+ }
+ }
+
+ // Load the OS-dependent library from the Jar file.
+ private fun loadNativeLibrary() {
+ val packagePath =
+ SQLiteJDBCLoader::class.java.getPackage().name.replace(".", "/")
+ val nativeLibraryPath =
+ "/$packagePath/native/${OSInfo.getNativeLibFolderPathForCurrentOS()}"
+ val nativeLibraryName = let {
+ val libName = System.mapLibraryName("sqlitejdbc")
+ .apply { replace("dylib", "jnilib") }
+ if (hasResource("$nativeLibraryPath/$libName")) {
+ return@let libName
+ }
+ if (OSInfo.getOSName() == "Mac") {
+ // Fix for openjdk7 for Mac
+ val altLibName = "libsqlitejdbc.jnilib"
+ if (hasResource("$nativeLibraryPath/$altLibName")) {
+ return@let altLibName
+ }
+ }
+ error(
+ "No native library is found for os.name=${OSInfo.getOSName()} and " +
+ "os.arch=${OSInfo.getArchName()}. path=$nativeLibraryPath"
+ )
+ }
+
+ val extractedNativeLibraryFile = try {
+ extractNativeLibrary(nativeLibraryPath, nativeLibraryName, tempDir.absolutePath)
+ } catch (ex: IOException) {
+ throw RuntimeException("Couldn't extract native SQLite library.", ex)
+ }
+ try {
+ @Suppress("UnsafeDynamicallyLoadedCode") // Loading an from an absolute path.
+ System.load(extractedNativeLibraryFile.absolutePath)
+ } catch (ex: UnsatisfiedLinkError) {
+ throw RuntimeException("Couldn't load native SQLite library.", ex)
+ }
+ }
+
+ private fun extractNativeLibrary(
+ libraryPath: String,
+ libraryName: String,
+ targetDirPath: String
+ ): File {
+ val libraryFilePath = "$libraryPath/$libraryName"
+ // Include arch name in temporary filename in order to avoid conflicts when multiple JVMs
+ // with different architectures are running.
+ val outputLibraryFile = File(
+ targetDirPath,
+ "sqlite-$version-${UUID.randomUUID()}-$libraryName"
+ ).apply { deleteOnExit() }
+ val outputLibraryLckFile = File(
+ targetDirPath,
+ "${outputLibraryFile.name}.lck"
+ ).apply { deleteOnExit() }
+ if (!outputLibraryLckFile.exists()) {
+ outputLibraryLckFile.outputStream().close()
+ }
+ getResourceAsStream(libraryFilePath).use { inputStream ->
+ outputLibraryFile.outputStream().use { outputStream ->
+ inputStream.copyTo(outputStream)
+ }
+ }
+ // Set executable flag (x) to enable loading the library.
+ outputLibraryFile.setReadable(true)
+ outputLibraryFile.setExecutable(true)
+ return outputLibraryFile
+ }
+
+ private fun hasResource(path: String) = SQLiteJDBCLoader::class.java.getResource(path) != null
+
+ // Replacement of java.lang.Class#getResourceAsStream(String) to disable sharing the resource
+ // stream in multiple class loaders and specifically to avoid
+ // https://bugs.openjdk.java.net/browse/JDK-8205976
+ private fun getResourceAsStream(name: String): InputStream {
+ // Remove leading '/' since all our resource paths include a leading directory
+ // See: https://github.com/openjdk/jdk/blob/jdk-11+0/src/java.base/share/classes/java/lang/Class.java#L2573
+ val resolvedName = name.drop(1)
+ val url = SQLiteJDBCLoader::class.java.classLoader.getResource(resolvedName)
+ ?: throw IOException("Resource '$resolvedName' could not be found.")
+ return url.openConnection().apply {
+ defaultUseCaches = false
+ }.getInputStream()
+ }
+}
\ No newline at end of file
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/verifier/NativeSQLiteLoaderTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/verifier/NativeSQLiteLoaderTest.kt
new file mode 100644
index 0000000..8cf547b
--- /dev/null
+++ b/room/room-compiler/src/test/kotlin/androidx/room/verifier/NativeSQLiteLoaderTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.verifier
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import java.io.File
+import java.net.URL
+import java.net.URLClassLoader
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicInteger
+import java.util.jar.JarEntry
+import java.util.jar.JarOutputStream
+
+@RunWith(JUnit4::class)
+class NativeSQLiteLoaderTest {
+
+ @Test
+ fun multipleClassLoader() {
+ // Get current classpath
+ val stringUrls = System.getProperty("java.class.path")!!
+ .split(System.getProperty("path.separator")!!).toTypedArray()
+ // Find classes under test.
+ val targetDirName = "room-compiler/build/classes/kotlin/main"
+ val classesDirPath = stringUrls.first { it.contains(targetDirName) }
+ // Create a JAR file out the classes and resources
+ val jarFile = File.createTempFile("jar-for-test-", ".jar")
+ createJar(classesDirPath, jarFile)
+ val jarUrl = URL("file://${jarFile.absolutePath}")
+ // Find Kotlin stdlibs (will need them to load class under test)
+ val kotlinStdbLibUrls = stringUrls
+ .filter { it.contains("kotlin-stdlib") && it.endsWith(".jar") }
+ .map { URL("file://$it") }
+ // Also find sqlite-jdbc since it is a hard dep of NativeSQLiteLoader
+ val sqliteJdbcJarUrl = stringUrls
+ .filter { it.contains("sqlite-jdbc") && it.endsWith(".jar") }
+ .map { URL("file://$it") }
+ // Spawn a few threads and have them all in parallel load the native lib
+ val completedThreads = AtomicInteger(0)
+ val numOfThreads = 8
+ val pool = Executors.newFixedThreadPool(numOfThreads)
+ val loadedClasses = arrayOfNulls<Class<*>>(numOfThreads)
+ for (i in 1..numOfThreads) {
+ pool.execute {
+ try {
+ Thread.sleep((i * 10).toLong())
+ // Create an isolated class loader, it should load *different* instances
+ // of NativeSQLiteLoader.class
+ val classLoader = URLClassLoader(
+ (kotlinStdbLibUrls + sqliteJdbcJarUrl + jarUrl).toTypedArray(),
+ ClassLoader.getSystemClassLoader().parent
+ )
+ val clazz =
+ classLoader.loadClass("androidx.room.verifier.NativeSQLiteLoader")
+ clazz.getDeclaredMethod("load").invoke(null)
+ classLoader.close()
+ loadedClasses[i - 1] = clazz
+ } catch (e: Throwable) {
+ e.printStackTrace()
+ fail(e.message)
+ }
+ completedThreads.incrementAndGet()
+ }
+ }
+ // Verify all threads completed
+ pool.shutdown()
+ pool.awaitTermination(3, TimeUnit.SECONDS)
+ assertThat(completedThreads.get()).isEqualTo(numOfThreads)
+ // Verify all loaded classes are different from each other
+ loadedClasses.forEachIndexed { i, clazz1 ->
+ loadedClasses.forEachIndexed { j, clazz2 ->
+ if (i == j) {
+ assertThat(clazz1).isEqualTo(clazz2)
+ } else {
+ assertThat(clazz1).isNotEqualTo(clazz2)
+ }
+ }
+ }
+ }
+
+ private fun createJar(inputDir: String, outputFile: File) {
+ JarOutputStream(outputFile.outputStream()).use {
+ addJarEntry(File(inputDir), inputDir, it)
+ }
+ }
+
+ private fun addJarEntry(source: File, changeDir: String, target: JarOutputStream) {
+ if (source.isDirectory) {
+ var name = source.path.replace("\\", "/")
+ if (name.isNotEmpty()) {
+ if (!name.endsWith("/")) {
+ name += "/"
+ }
+ val entry = JarEntry(name.substring(changeDir.length + 1))
+ entry.time = source.lastModified()
+ target.putNextEntry(entry)
+ target.closeEntry()
+ }
+ source.listFiles()!!.forEach { nestedFile ->
+ addJarEntry(nestedFile, changeDir, target)
+ }
+ } else if (source.isFile) {
+ val entry = JarEntry(
+ source.path.replace("\\", "/").substring(changeDir.length + 1)
+ )
+ entry.time = source.lastModified()
+ target.putNextEntry(entry)
+ source.inputStream().use { inputStream ->
+ inputStream.copyTo(target)
+ }
+ target.closeEntry()
+ }
+ }
+}
\ No newline at end of file
diff --git a/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt b/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt
index 8773399..d9b29cd 100644
--- a/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt
+++ b/text/text/src/main/java/androidx/compose/ui/text/android/LayoutIntrinsics.kt
@@ -22,7 +22,6 @@
import android.text.TextPaint
import androidx.compose.ui.text.android.style.LetterSpacingSpanEm
import androidx.compose.ui.text.android.style.LetterSpacingSpanPx
-import androidx.compose.ui.text.android.style.LineHeightSpan
import java.text.BreakIterator
import java.util.PriorityQueue
@@ -139,6 +138,5 @@
textPaint.letterSpacing != 0f ||
charSequence.hasSpan(LetterSpacingSpanPx::class.java) ||
charSequence.hasSpan(LetterSpacingSpanEm::class.java)
- ) &&
- charSequence.hasSpan(LineHeightSpan::class.java)
+ )
}
\ No newline at end of file
diff --git a/window/window-testing/api/current.txt b/window/window-testing/api/current.txt
index e0d15ce..b564bd4 100644
--- a/window/window-testing/api/current.txt
+++ b/window/window-testing/api/current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package androidx.window.test {
+package androidx.window.testing {
public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
ctor public WindowLayoutInfoPublisherRule();
diff --git a/window/window-testing/api/public_plus_experimental_current.txt b/window/window-testing/api/public_plus_experimental_current.txt
index f00e796..729cf86 100644
--- a/window/window-testing/api/public_plus_experimental_current.txt
+++ b/window/window-testing/api/public_plus_experimental_current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package androidx.window.test {
+package androidx.window.testing {
public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
ctor public WindowLayoutInfoPublisherRule();
diff --git a/window/window-testing/api/restricted_current.txt b/window/window-testing/api/restricted_current.txt
index e0d15ce..b564bd4 100644
--- a/window/window-testing/api/restricted_current.txt
+++ b/window/window-testing/api/restricted_current.txt
@@ -1,5 +1,5 @@
// Signature format: 4.0
-package androidx.window.test {
+package androidx.window.testing {
public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
ctor public WindowLayoutInfoPublisherRule();
diff --git a/window/window-testing/src/androidTest/AndroidManifest.xml b/window/window-testing/src/androidTest/AndroidManifest.xml
index 7d587da..5d5fa1c 100644
--- a/window/window-testing/src/androidTest/AndroidManifest.xml
+++ b/window/window-testing/src/androidTest/AndroidManifest.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.window.test">
+ package="androidx.window.testing">
<application>
<activity android:name="TestActivity"/>
</application>
diff --git a/window/window-testing/src/androidTest/java/androidx/window/test/TestActivity.kt b/window/window-testing/src/androidTest/java/androidx/window/testing/TestActivity.kt
similarity index 95%
rename from window/window-testing/src/androidTest/java/androidx/window/test/TestActivity.kt
rename to window/window-testing/src/androidTest/java/androidx/window/testing/TestActivity.kt
index 3d934fd..510278d 100644
--- a/window/window-testing/src/androidTest/java/androidx/window/test/TestActivity.kt
+++ b/window/window-testing/src/androidTest/java/androidx/window/testing/TestActivity.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.window.test
+package androidx.window.testing
import android.app.Activity
diff --git a/window/window-testing/src/androidTest/java/androidx/window/test/WindowLayoutInfoPublisherRuleTest.kt b/window/window-testing/src/androidTest/java/androidx/window/testing/WindowLayoutInfoPublisherRuleTest.kt
similarity index 98%
rename from window/window-testing/src/androidTest/java/androidx/window/test/WindowLayoutInfoPublisherRuleTest.kt
rename to window/window-testing/src/androidTest/java/androidx/window/testing/WindowLayoutInfoPublisherRuleTest.kt
index a93682b..51dac78 100644
--- a/window/window-testing/src/androidTest/java/androidx/window/test/WindowLayoutInfoPublisherRuleTest.kt
+++ b/window/window-testing/src/androidTest/java/androidx/window/testing/WindowLayoutInfoPublisherRuleTest.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.window.test
+package androidx.window.testing
import android.graphics.Rect
import androidx.test.ext.junit.rules.ActivityScenarioRule
diff --git a/window/window-testing/src/main/AndroidManifest.xml b/window/window-testing/src/main/AndroidManifest.xml
index 4bd698f..9582ba4 100644
--- a/window/window-testing/src/main/AndroidManifest.xml
+++ b/window/window-testing/src/main/AndroidManifest.xml
@@ -15,5 +15,5 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.window.test">
+ package="androidx.window.testing">
</manifest>
\ No newline at end of file
diff --git a/window/window-testing/src/main/java/androidx/window/test/PublishLayoutInfoRepo.kt b/window/window-testing/src/main/java/androidx/window/testing/PublishLayoutInfoRepo.kt
similarity index 96%
rename from window/window-testing/src/main/java/androidx/window/test/PublishLayoutInfoRepo.kt
rename to window/window-testing/src/main/java/androidx/window/testing/PublishLayoutInfoRepo.kt
index b3591df..476f250 100644
--- a/window/window-testing/src/main/java/androidx/window/test/PublishLayoutInfoRepo.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/PublishLayoutInfoRepo.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.window.test
+package androidx.window.testing
import androidx.window.WindowInfoRepo
import androidx.window.WindowLayoutInfo
diff --git a/window/window-testing/src/main/java/androidx/window/test/PublishWindowInfoRepoDecorator.kt b/window/window-testing/src/main/java/androidx/window/testing/PublishWindowInfoRepoDecorator.kt
similarity index 96%
rename from window/window-testing/src/main/java/androidx/window/test/PublishWindowInfoRepoDecorator.kt
rename to window/window-testing/src/main/java/androidx/window/testing/PublishWindowInfoRepoDecorator.kt
index 7cf34ba..c26b204 100644
--- a/window/window-testing/src/main/java/androidx/window/test/PublishWindowInfoRepoDecorator.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/PublishWindowInfoRepoDecorator.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.window.test
+package androidx.window.testing
import androidx.window.WindowInfoRepo
import androidx.window.WindowInfoRepoDecorator
diff --git a/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisher.kt b/window/window-testing/src/main/java/androidx/window/testing/WindowLayoutInfoPublisher.kt
similarity index 97%
rename from window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisher.kt
rename to window/window-testing/src/main/java/androidx/window/testing/WindowLayoutInfoPublisher.kt
index 2261e68..ac1766f 100644
--- a/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisher.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/WindowLayoutInfoPublisher.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.window.test
+package androidx.window.testing
import androidx.window.WindowInfoRepo
import androidx.window.WindowLayoutInfo
diff --git a/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisherRule.kt b/window/window-testing/src/main/java/androidx/window/testing/WindowLayoutInfoPublisherRule.kt
similarity index 98%
rename from window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisherRule.kt
rename to window/window-testing/src/main/java/androidx/window/testing/WindowLayoutInfoPublisherRule.kt
index f9e92fc..3194bc2 100644
--- a/window/window-testing/src/main/java/androidx/window/test/WindowLayoutInfoPublisherRule.kt
+++ b/window/window-testing/src/main/java/androidx/window/testing/WindowLayoutInfoPublisherRule.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package androidx.window.test
+package androidx.window.testing
import androidx.window.WindowInfoRepo
import androidx.window.WindowLayoutInfo
diff --git a/window/window/src/androidTest/AndroidManifest.xml b/window/window/src/androidTest/AndroidManifest.xml
index d5eba48..5efaf0f7 100644
--- a/window/window/src/androidTest/AndroidManifest.xml
+++ b/window/window/src/androidTest/AndroidManifest.xml
@@ -15,7 +15,7 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="androidx.window.test">
+ package="androidx.window.testing">
<application>
<uses-library android:name="androidx.window.extension" android:required="false" />