Merge "Add XMethodType.typeVariables APIs" into androidx-main
diff --git a/annotation/annotation/api/1.7.0-beta01.txt b/annotation/annotation/api/1.7.0-beta01.txt
new file mode 100644
index 0000000..71556c1
--- /dev/null
+++ b/annotation/annotation/api/1.7.0-beta01.txt
@@ -0,0 +1,369 @@
+// Signature format: 4.0
+package androidx.annotation {
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AnimRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AnimatorRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AnyRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface AnyThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface ArrayRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AttrRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface BinderThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface BoolRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface CallSuper {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface CheckResult {
+ method public abstract String suggest() default "";
+ property public abstract String suggest;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface ChecksSdkIntAtLeast {
+ method public abstract int api() default -1;
+ method public abstract String codename() default "";
+ method public abstract int extension() default 0;
+ method public abstract int lambda() default -1;
+ method public abstract int parameter() default -1;
+ property public abstract int api;
+ property public abstract String codename;
+ property public abstract int extension;
+ property public abstract int lambda;
+ property public abstract int parameter;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface ColorInt {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface ColorLong {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface ColorRes {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.CONSTRUCTOR) public @interface ContentView {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.CONSTRUCTOR}) public @interface DeprecatedSinceApi {
+ method public abstract int api();
+ method public abstract String message() default "";
+ property public abstract int api;
+ property public abstract String message;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface DimenRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface Dimension {
+ method public abstract int unit() default androidx.annotation.Dimension.PX;
+ property public abstract int unit;
+ field public static final androidx.annotation.Dimension.Companion Companion;
+ field public static final int DP = 0; // 0x0
+ field public static final int PX = 1; // 0x1
+ field public static final int SP = 2; // 0x2
+ }
+
+ public static final class Dimension.Companion {
+ field public static final int DP = 0; // 0x0
+ field public static final int PX = 1; // 0x1
+ field public static final int SP = 2; // 0x2
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public @interface Discouraged {
+ method public abstract String message();
+ property public abstract String message;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface DisplayContext {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface DoNotInline {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface DrawableRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface EmptySuper {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface FloatRange {
+ method public abstract double from() default kotlin.jvm.internal.DoubleCompanionObject.NEGATIVE_INFINITY;
+ method public abstract boolean fromInclusive() default true;
+ method public abstract double to() default kotlin.jvm.internal.DoubleCompanionObject.POSITIVE_INFINITY;
+ method public abstract boolean toInclusive() default true;
+ property public abstract double from;
+ property public abstract boolean fromInclusive;
+ property public abstract double to;
+ property public abstract boolean toInclusive;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface FontRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface FractionRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface GravityInt {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface GuardedBy {
+ method public abstract String value();
+ property public abstract String value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface HalfFloat {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface IdRes {
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface InspectableProperty {
+ method @Deprecated public abstract int attributeId() default 0;
+ method @Deprecated public abstract androidx.annotation.InspectableProperty.EnumEntry[] enumMapping();
+ method @Deprecated public abstract androidx.annotation.InspectableProperty.FlagEntry[] flagMapping();
+ method @Deprecated public abstract boolean hasAttributeId() default true;
+ method @Deprecated public abstract String name() default "";
+ method @Deprecated public abstract androidx.annotation.InspectableProperty.ValueType valueType() default androidx.annotation.InspectableProperty.ValueType.INFERRED;
+ property @Deprecated public abstract int attributeId;
+ property @Deprecated public abstract androidx.annotation.InspectableProperty.EnumEntry[] enumMapping;
+ property @Deprecated public abstract androidx.annotation.InspectableProperty.FlagEntry[] flagMapping;
+ property @Deprecated public abstract boolean hasAttributeId;
+ property @Deprecated public abstract String name;
+ property @Deprecated public abstract androidx.annotation.InspectableProperty.ValueType valueType;
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface InspectableProperty.EnumEntry {
+ method @Deprecated public abstract String name();
+ method @Deprecated public abstract int value();
+ property @Deprecated public abstract String name;
+ property @Deprecated public abstract int value;
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface InspectableProperty.FlagEntry {
+ method @Deprecated public abstract int mask() default 0;
+ method @Deprecated public abstract String name();
+ method @Deprecated public abstract int target();
+ property @Deprecated public abstract int mask;
+ property @Deprecated public abstract String name;
+ property @Deprecated public abstract int target;
+ }
+
+ @Deprecated public enum InspectableProperty.ValueType {
+ method @Deprecated public static androidx.annotation.InspectableProperty.ValueType valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.annotation.InspectableProperty.ValueType[] values();
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType COLOR;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType GRAVITY;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType INFERRED;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType INT_ENUM;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType INT_FLAG;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType NONE;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType RESOURCE_ID;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS) public @interface IntDef {
+ method public abstract boolean flag() default false;
+ method public abstract boolean open() default false;
+ method public abstract int[] value();
+ property public abstract boolean flag;
+ property public abstract boolean open;
+ property public abstract int[] value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface IntRange {
+ method public abstract long from() default kotlin.jvm.internal.LongCompanionObject.MIN_VALUE;
+ method public abstract long to() default kotlin.jvm.internal.LongCompanionObject.MAX_VALUE;
+ property public abstract long from;
+ property public abstract long to;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface IntegerRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface InterpolatorRes {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.PACKAGE, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface Keep {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface LayoutRes {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS) public @interface LongDef {
+ method public abstract boolean flag() default false;
+ method public abstract boolean open() default false;
+ method public abstract long[] value();
+ property public abstract boolean flag;
+ property public abstract boolean open;
+ property public abstract long[] value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface MainThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface MenuRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface NavigationRes {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FILE}) public @interface NonNull {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface NonUiContext {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FILE}) public @interface Nullable {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CLASS}) public @interface OpenForTesting {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface PluralsRes {
+ }
+
+ @Dimension(unit=androidx.annotation.Dimension.Companion.PX) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface Px {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface RawRes {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public @interface RequiresApi {
+ method public abstract int api() default 1;
+ method public abstract int value() default 1;
+ property public abstract int api;
+ property public abstract int value;
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public @interface RequiresExtension {
+ method public abstract int extension();
+ method public abstract int version();
+ property public abstract int extension;
+ property public abstract int version;
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public static @interface RequiresExtension.Container {
+ method public abstract androidx.annotation.RequiresExtension[] value();
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR}) public @interface RequiresFeature {
+ method public abstract String enforcement();
+ method public abstract String name();
+ property public abstract String enforcement;
+ property public abstract String name;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface RequiresPermission {
+ method public abstract String[] allOf();
+ method public abstract String[] anyOf();
+ method public abstract boolean conditional() default false;
+ method public abstract String value() default "";
+ property public abstract String[] allOf;
+ property public abstract String[] anyOf;
+ property public abstract boolean conditional;
+ property public abstract String value;
+ }
+
+ @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public static @interface RequiresPermission.Read {
+ method public abstract androidx.annotation.RequiresPermission value() default androidx.annotation.RequiresPermission();
+ property public abstract androidx.annotation.RequiresPermission value;
+ }
+
+ @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public static @interface RequiresPermission.Write {
+ method public abstract androidx.annotation.RequiresPermission value() default androidx.annotation.RequiresPermission();
+ property public abstract androidx.annotation.RequiresPermission value;
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public @interface RestrictTo {
+ method public abstract androidx.annotation.RestrictTo.Scope[] value();
+ property public abstract androidx.annotation.RestrictTo.Scope[] value;
+ }
+
+ public enum RestrictTo.Scope {
+ method public static androidx.annotation.RestrictTo.Scope valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.annotation.RestrictTo.Scope[] values();
+ enum_constant @Deprecated public static final androidx.annotation.RestrictTo.Scope GROUP_ID;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY_GROUP;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY_GROUP_PREFIX;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope SUBCLASSES;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope TESTS;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.CLASS}) public @interface ReturnThis {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface Size {
+ method public abstract long max() default kotlin.jvm.internal.LongCompanionObject.MAX_VALUE;
+ method public abstract long min() default kotlin.jvm.internal.LongCompanionObject.MIN_VALUE;
+ method public abstract long multiple() default 1;
+ method public abstract long value() default -1;
+ property public abstract long max;
+ property public abstract long min;
+ property public abstract long multiple;
+ property public abstract long value;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS) public @interface StringDef {
+ method public abstract boolean open() default false;
+ method public abstract String[] value();
+ property public abstract boolean open;
+ property public abstract String[] value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface StringRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface StyleRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface StyleableRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface TransitionRes {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface UiContext {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface UiThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface VisibleForTesting {
+ method public abstract int otherwise() default androidx.annotation.VisibleForTesting.PRIVATE;
+ property public abstract int otherwise;
+ field public static final androidx.annotation.VisibleForTesting.Companion Companion;
+ field public static final int NONE = 5; // 0x5
+ field public static final int PACKAGE_PRIVATE = 3; // 0x3
+ field public static final int PRIVATE = 2; // 0x2
+ field public static final int PROTECTED = 4; // 0x4
+ }
+
+ public static final class VisibleForTesting.Companion {
+ field public static final int NONE = 5; // 0x5
+ field public static final int PACKAGE_PRIVATE = 3; // 0x3
+ field public static final int PRIVATE = 2; // 0x2
+ field public static final int PROTECTED = 4; // 0x4
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface WorkerThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface XmlRes {
+ }
+
+}
+
diff --git a/annotation/annotation/api/restricted_1.7.0-beta01.txt b/annotation/annotation/api/restricted_1.7.0-beta01.txt
new file mode 100644
index 0000000..71556c1
--- /dev/null
+++ b/annotation/annotation/api/restricted_1.7.0-beta01.txt
@@ -0,0 +1,369 @@
+// Signature format: 4.0
+package androidx.annotation {
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AnimRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AnimatorRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AnyRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface AnyThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface ArrayRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface AttrRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface BinderThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface BoolRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface CallSuper {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface CheckResult {
+ method public abstract String suggest() default "";
+ property public abstract String suggest;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface ChecksSdkIntAtLeast {
+ method public abstract int api() default -1;
+ method public abstract String codename() default "";
+ method public abstract int extension() default 0;
+ method public abstract int lambda() default -1;
+ method public abstract int parameter() default -1;
+ property public abstract int api;
+ property public abstract String codename;
+ property public abstract int extension;
+ property public abstract int lambda;
+ property public abstract int parameter;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface ColorInt {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface ColorLong {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface ColorRes {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.CONSTRUCTOR) public @interface ContentView {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.CONSTRUCTOR}) public @interface DeprecatedSinceApi {
+ method public abstract int api();
+ method public abstract String message() default "";
+ property public abstract int api;
+ property public abstract String message;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface DimenRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface Dimension {
+ method public abstract int unit() default androidx.annotation.Dimension.PX;
+ property public abstract int unit;
+ field public static final androidx.annotation.Dimension.Companion Companion;
+ field public static final int DP = 0; // 0x0
+ field public static final int PX = 1; // 0x1
+ field public static final int SP = 2; // 0x2
+ }
+
+ public static final class Dimension.Companion {
+ field public static final int DP = 0; // 0x0
+ field public static final int PX = 1; // 0x1
+ field public static final int SP = 2; // 0x2
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public @interface Discouraged {
+ method public abstract String message();
+ property public abstract String message;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface DisplayContext {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface DoNotInline {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface DrawableRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface EmptySuper {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface FloatRange {
+ method public abstract double from() default kotlin.jvm.internal.DoubleCompanionObject.NEGATIVE_INFINITY;
+ method public abstract boolean fromInclusive() default true;
+ method public abstract double to() default kotlin.jvm.internal.DoubleCompanionObject.POSITIVE_INFINITY;
+ method public abstract boolean toInclusive() default true;
+ property public abstract double from;
+ property public abstract boolean fromInclusive;
+ property public abstract double to;
+ property public abstract boolean toInclusive;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface FontRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface FractionRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface GravityInt {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface GuardedBy {
+ method public abstract String value();
+ property public abstract String value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FIELD}) public @interface HalfFloat {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface IdRes {
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER}) public @interface InspectableProperty {
+ method @Deprecated public abstract int attributeId() default 0;
+ method @Deprecated public abstract androidx.annotation.InspectableProperty.EnumEntry[] enumMapping();
+ method @Deprecated public abstract androidx.annotation.InspectableProperty.FlagEntry[] flagMapping();
+ method @Deprecated public abstract boolean hasAttributeId() default true;
+ method @Deprecated public abstract String name() default "";
+ method @Deprecated public abstract androidx.annotation.InspectableProperty.ValueType valueType() default androidx.annotation.InspectableProperty.ValueType.INFERRED;
+ property @Deprecated public abstract int attributeId;
+ property @Deprecated public abstract androidx.annotation.InspectableProperty.EnumEntry[] enumMapping;
+ property @Deprecated public abstract androidx.annotation.InspectableProperty.FlagEntry[] flagMapping;
+ property @Deprecated public abstract boolean hasAttributeId;
+ property @Deprecated public abstract String name;
+ property @Deprecated public abstract androidx.annotation.InspectableProperty.ValueType valueType;
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface InspectableProperty.EnumEntry {
+ method @Deprecated public abstract String name();
+ method @Deprecated public abstract int value();
+ property @Deprecated public abstract String name;
+ property @Deprecated public abstract int value;
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS}) public static @interface InspectableProperty.FlagEntry {
+ method @Deprecated public abstract int mask() default 0;
+ method @Deprecated public abstract String name();
+ method @Deprecated public abstract int target();
+ property @Deprecated public abstract int mask;
+ property @Deprecated public abstract String name;
+ property @Deprecated public abstract int target;
+ }
+
+ @Deprecated public enum InspectableProperty.ValueType {
+ method @Deprecated public static androidx.annotation.InspectableProperty.ValueType valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method @Deprecated public static androidx.annotation.InspectableProperty.ValueType[] values();
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType COLOR;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType GRAVITY;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType INFERRED;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType INT_ENUM;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType INT_FLAG;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType NONE;
+ enum_constant @Deprecated public static final androidx.annotation.InspectableProperty.ValueType RESOURCE_ID;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS) public @interface IntDef {
+ method public abstract boolean flag() default false;
+ method public abstract boolean open() default false;
+ method public abstract int[] value();
+ property public abstract boolean flag;
+ property public abstract boolean open;
+ property public abstract int[] value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface IntRange {
+ method public abstract long from() default kotlin.jvm.internal.LongCompanionObject.MIN_VALUE;
+ method public abstract long to() default kotlin.jvm.internal.LongCompanionObject.MAX_VALUE;
+ property public abstract long from;
+ property public abstract long to;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface IntegerRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface InterpolatorRes {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.PACKAGE, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface Keep {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface LayoutRes {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS) public @interface LongDef {
+ method public abstract boolean flag() default false;
+ method public abstract boolean open() default false;
+ method public abstract long[] value();
+ property public abstract boolean flag;
+ property public abstract boolean open;
+ property public abstract long[] value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface MainThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface MenuRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface NavigationRes {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FILE}) public @interface NonNull {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface NonUiContext {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.LOCAL_VARIABLE, java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FILE}) public @interface Nullable {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CLASS}) public @interface OpenForTesting {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface PluralsRes {
+ }
+
+ @Dimension(unit=androidx.annotation.Dimension.Companion.PX) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface Px {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface RawRes {
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public @interface RequiresApi {
+ method public abstract int api() default 1;
+ method public abstract int value() default 1;
+ property public abstract int api;
+ property public abstract int value;
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public @interface RequiresExtension {
+ method public abstract int extension();
+ method public abstract int version();
+ property public abstract int extension;
+ property public abstract int version;
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public static @interface RequiresExtension.Container {
+ method public abstract androidx.annotation.RequiresExtension[] value();
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR}) public @interface RequiresFeature {
+ method public abstract String enforcement();
+ method public abstract String name();
+ property public abstract String enforcement;
+ property public abstract String name;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface RequiresPermission {
+ method public abstract String[] allOf();
+ method public abstract String[] anyOf();
+ method public abstract boolean conditional() default false;
+ method public abstract String value() default "";
+ property public abstract String[] allOf;
+ property public abstract String[] anyOf;
+ property public abstract boolean conditional;
+ property public abstract String value;
+ }
+
+ @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public static @interface RequiresPermission.Read {
+ method public abstract androidx.annotation.RequiresPermission value() default androidx.annotation.RequiresPermission();
+ property public abstract androidx.annotation.RequiresPermission value;
+ }
+
+ @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public static @interface RequiresPermission.Write {
+ method public abstract androidx.annotation.RequiresPermission value() default androidx.annotation.RequiresPermission();
+ property public abstract androidx.annotation.RequiresPermission value;
+ }
+
+ @java.lang.annotation.Target({java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.PACKAGE}) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.FILE}) public @interface RestrictTo {
+ method public abstract androidx.annotation.RestrictTo.Scope[] value();
+ property public abstract androidx.annotation.RestrictTo.Scope[] value;
+ }
+
+ public enum RestrictTo.Scope {
+ method public static androidx.annotation.RestrictTo.Scope valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.annotation.RestrictTo.Scope[] values();
+ enum_constant @Deprecated public static final androidx.annotation.RestrictTo.Scope GROUP_ID;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY_GROUP;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY_GROUP_PREFIX;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope SUBCLASSES;
+ enum_constant public static final androidx.annotation.RestrictTo.Scope TESTS;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.CLASS}) public @interface ReturnThis {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS}) public @interface Size {
+ method public abstract long max() default kotlin.jvm.internal.LongCompanionObject.MAX_VALUE;
+ method public abstract long min() default kotlin.jvm.internal.LongCompanionObject.MIN_VALUE;
+ method public abstract long multiple() default 1;
+ method public abstract long value() default -1;
+ property public abstract long max;
+ property public abstract long min;
+ property public abstract long multiple;
+ property public abstract long value;
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS) public @interface StringDef {
+ method public abstract boolean open() default false;
+ method public abstract String[] value();
+ property public abstract boolean open;
+ property public abstract String[] value;
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface StringRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface StyleRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface StyleableRes {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface TransitionRes {
+ }
+
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD}) public @interface UiContext {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface UiThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface VisibleForTesting {
+ method public abstract int otherwise() default androidx.annotation.VisibleForTesting.PRIVATE;
+ property public abstract int otherwise;
+ field public static final androidx.annotation.VisibleForTesting.Companion Companion;
+ field public static final int NONE = 5; // 0x5
+ field public static final int PACKAGE_PRIVATE = 3; // 0x3
+ field public static final int PRIVATE = 2; // 0x2
+ field public static final int PROTECTED = 4; // 0x4
+ }
+
+ public static final class VisibleForTesting.Companion {
+ field public static final int NONE = 5; // 0x5
+ field public static final int PACKAGE_PRIVATE = 3; // 0x3
+ field public static final int PRIVATE = 2; // 0x2
+ field public static final int PROTECTED = 4; // 0x4
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.CONSTRUCTOR, kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER}) public @interface WorkerThread {
+ }
+
+ @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.PROPERTY_SETTER, kotlin.annotation.AnnotationTarget.VALUE_PARAMETER, kotlin.annotation.AnnotationTarget.FIELD, kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE}) public @interface XmlRes {
+ }
+
+}
+
diff --git a/appactions/interaction/interaction-capabilities-core/lint-baseline.xml b/appactions/interaction/interaction-capabilities-core/lint-baseline.xml
deleted file mode 100644
index 845b3c4..0000000
--- a/appactions/interaction/interaction-capabilities-core/lint-baseline.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues name="AGP (8.1.0-beta02)" by="lint 8.1.0-beta02" client="gradle" dependencies="false"
- format="6" type="baseline" variant="all" version="8.1.0-beta02">
-
- <!-- Need to use reflection to dynamically access serializers based on type-name. These
- serializers may be coming from a downstream artifact and are not available at compile-time.
- This also aids in a binary-bloat optimization where all serializers start off a dead code and
- then we instruct proguard to only retain the serializers for types that are explicitly
- referenced and prune others.
- -->
- <issue
- errorLine1=" .map { it.invoke(null) as BuiltInTypeSerializer<*> }"
- errorLine2=" ~~~~~~~~~~~~~~~"
- id="BanUncheckedReflection"
- message="Calling `Method.invoke` without an SDK check">
- <location
- file="src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt" />
- </issue>
-
-</issues>
diff --git a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt
index 0d0d278..f80c2f3 100644
--- a/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt
+++ b/appactions/interaction/interaction-capabilities-core/src/main/java/androidx/appactions/interaction/capabilities/serializers/types/BuiltInTypeSerializerRegistry.kt
@@ -52,6 +52,7 @@
* [BuiltInTypeSerializer].
* @param getClassOrNull Functor that returns a class ref given its canonical name, or null.
*/
+@Suppress("BanUncheckedReflection")
class BuiltInTypeSerializerRegistry(
serializerRegistryClassNames: List<String>,
getClassOrNull: (canonicalName: String) -> Class<*>?
@@ -61,6 +62,11 @@
Collections.synchronizedMap(mutableMapOf())
init {
+ // Need to use reflection to dynamically access serializers based on type-name. These
+ // serializers may be coming from a downstream artifact and are not available at
+ // compile-time. This also aids in a binary-bloat optimization where all serializers start
+ // off a dead code and then we instruct proguard to only retain the serializers for types
+ // that are explicitly referenced and prune others.
val serializers =
serializerRegistryClassNames
// object AllProductivitySerializers
diff --git a/appsearch/appsearch-builtin-types/api/current.txt b/appsearch/appsearch-builtin-types/api/current.txt
index ceffd8c..ed35276 100644
--- a/appsearch/appsearch-builtin-types/api/current.txt
+++ b/appsearch/appsearch-builtin-types/api/current.txt
@@ -29,7 +29,7 @@
field public static final int COMPUTING_DEVICE_UNKNOWN = 0; // 0x0
}
- public static final class Alarm.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class Alarm.Builder {
ctor public Alarm.Builder(androidx.appsearch.builtintypes.Alarm);
ctor public Alarm.Builder(String, String);
method public androidx.appsearch.builtintypes.Alarm.Builder addAlternateName(String);
@@ -37,6 +37,7 @@
method public androidx.appsearch.builtintypes.Alarm build();
method public androidx.appsearch.builtintypes.Alarm.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Alarm.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.Alarm.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.Alarm.Builder setBlackoutPeriodEndDate(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setBlackoutPeriodStartDate(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setComputingDevice(int);
@@ -51,6 +52,7 @@
method public androidx.appsearch.builtintypes.Alarm.Builder setMinute(@IntRange(from=0, to=59) int);
method public androidx.appsearch.builtintypes.Alarm.Builder setName(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setNextInstance(androidx.appsearch.builtintypes.AlarmInstance?);
+ method public androidx.appsearch.builtintypes.Alarm.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Alarm.Builder setPreviousInstance(androidx.appsearch.builtintypes.AlarmInstance?);
method public androidx.appsearch.builtintypes.Alarm.Builder setRingtone(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setShouldVibrate(boolean);
@@ -69,7 +71,7 @@
field public static final int STATUS_UNKNOWN = 0; // 0x0
}
- public static final class AlarmInstance.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class AlarmInstance.Builder {
ctor public AlarmInstance.Builder(androidx.appsearch.builtintypes.AlarmInstance);
ctor public AlarmInstance.Builder(String, String, String);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder addAlternateName(String);
@@ -77,12 +79,14 @@
method public androidx.appsearch.builtintypes.AlarmInstance build();
method public androidx.appsearch.builtintypes.AlarmInstance.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.AlarmInstance.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.AlarmInstance.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setDocumentScore(int);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setDocumentTtlMillis(long);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setImage(String?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.AlarmInstance.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setSnoozeDurationMillis(long);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setStatus(int);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setUrl(String?);
@@ -95,7 +99,7 @@
method public java.util.List<java.lang.String!> getTelephones();
}
- public static final class ContactPoint.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class ContactPoint.Builder {
ctor public ContactPoint.Builder(androidx.appsearch.builtintypes.ContactPoint);
ctor public ContactPoint.Builder(String, String, String);
method public androidx.appsearch.builtintypes.ContactPoint.Builder addAlternateName(String);
@@ -104,6 +108,7 @@
method public androidx.appsearch.builtintypes.ContactPoint.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.ContactPoint.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.ContactPoint.Builder setAddresses(java.util.List<java.lang.String!>);
+ method public androidx.appsearch.builtintypes.ContactPoint.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setDocumentScore(int);
@@ -111,6 +116,7 @@
method public androidx.appsearch.builtintypes.ContactPoint.Builder setEmails(java.util.List<java.lang.String!>);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setImage(String?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.ContactPoint.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setTelephones(java.util.List<java.lang.String!>);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setUrl(String?);
}
@@ -132,12 +138,14 @@
method public androidx.appsearch.builtintypes.ImageObject build();
method public androidx.appsearch.builtintypes.ImageObject.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.ImageObject.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.ImageObject.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.ImageObject.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setDocumentScore(int);
method public androidx.appsearch.builtintypes.ImageObject.Builder setDocumentTtlMillis(long);
method public androidx.appsearch.builtintypes.ImageObject.Builder setImage(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.ImageObject.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setSha256(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setThumbnailSha256(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setUrl(String?);
@@ -178,6 +186,7 @@
method public androidx.appsearch.builtintypes.Person.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.Person.Builder setAdditionalNames(java.util.List<androidx.appsearch.builtintypes.Person.AdditionalName!>);
method public androidx.appsearch.builtintypes.Person.Builder setAffiliations(java.util.List<java.lang.String!>);
+ method public androidx.appsearch.builtintypes.Person.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.Person.Builder setBot(boolean);
method public androidx.appsearch.builtintypes.Person.Builder setContactPoints(java.util.List<androidx.appsearch.builtintypes.ContactPoint!>);
method public androidx.appsearch.builtintypes.Person.Builder setCreationTimestampMillis(long);
@@ -193,6 +202,7 @@
method public androidx.appsearch.builtintypes.Person.Builder setMiddleName(String);
method public androidx.appsearch.builtintypes.Person.Builder setName(String?);
method public androidx.appsearch.builtintypes.Person.Builder setNotes(java.util.List<java.lang.String!>);
+ method public androidx.appsearch.builtintypes.Person.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Person.Builder setRelations(java.util.List<java.lang.String!>);
method public androidx.appsearch.builtintypes.Person.Builder setUrl(String?);
}
@@ -236,6 +246,7 @@
method public androidx.appsearch.builtintypes.Stopwatch.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Stopwatch.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.Stopwatch.Builder setAccumulatedDurationMillis(long);
+ method public androidx.appsearch.builtintypes.Stopwatch.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public androidx.appsearch.builtintypes.Stopwatch.Builder setBaseTimeMillis(android.content.Context, long, long);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setBaseTimeMillis(long, long, int);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setCreationTimestampMillis(long);
@@ -245,6 +256,7 @@
method public androidx.appsearch.builtintypes.Stopwatch.Builder setImage(String?);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setLaps(java.util.List<androidx.appsearch.builtintypes.StopwatchLap!>);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.Stopwatch.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setStatus(int);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setUrl(String?);
}
@@ -255,7 +267,7 @@
method public int getLapNumber();
}
- public static final class StopwatchLap.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class StopwatchLap.Builder {
ctor public StopwatchLap.Builder(androidx.appsearch.builtintypes.StopwatchLap);
ctor public StopwatchLap.Builder(String, String);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder addAlternateName(String);
@@ -264,6 +276,7 @@
method public androidx.appsearch.builtintypes.StopwatchLap.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.StopwatchLap.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setAccumulatedLapDurationMillis(long);
+ method public androidx.appsearch.builtintypes.StopwatchLap.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setDocumentScore(int);
@@ -272,6 +285,7 @@
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setLapDurationMillis(long);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setLapNumber(int);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.StopwatchLap.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setUrl(String?);
}
@@ -289,7 +303,7 @@
method public String? getUrl();
}
- public static final class Thing.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class Thing.Builder {
ctor public Thing.Builder(androidx.appsearch.builtintypes.Thing);
ctor public Thing.Builder(String, String);
method public androidx.appsearch.builtintypes.Thing.Builder addAlternateName(String);
@@ -297,12 +311,14 @@
method public androidx.appsearch.builtintypes.Thing build();
method public androidx.appsearch.builtintypes.Thing.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Thing.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.Thing.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.Thing.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.Thing.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.Thing.Builder setDocumentScore(int);
method public androidx.appsearch.builtintypes.Thing.Builder setDocumentTtlMillis(long);
method public androidx.appsearch.builtintypes.Thing.Builder setImage(String?);
method public androidx.appsearch.builtintypes.Thing.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.Thing.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Thing.Builder setUrl(String?);
}
@@ -336,6 +352,7 @@
method public androidx.appsearch.builtintypes.Timer build();
method public androidx.appsearch.builtintypes.Timer.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Timer.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.Timer.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public androidx.appsearch.builtintypes.Timer.Builder setBaseTimeMillis(android.content.Context, long, long);
method public androidx.appsearch.builtintypes.Timer.Builder setBaseTimeMillis(long, long, int);
method public androidx.appsearch.builtintypes.Timer.Builder setCreationTimestampMillis(long);
@@ -346,6 +363,7 @@
method public androidx.appsearch.builtintypes.Timer.Builder setImage(String?);
method public androidx.appsearch.builtintypes.Timer.Builder setName(String?);
method public androidx.appsearch.builtintypes.Timer.Builder setOriginalDurationMillis(long);
+ method public androidx.appsearch.builtintypes.Timer.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Timer.Builder setRemainingDurationMillis(long);
method public androidx.appsearch.builtintypes.Timer.Builder setRingtone(String?);
method public androidx.appsearch.builtintypes.Timer.Builder setShouldVibrate(boolean);
diff --git a/appsearch/appsearch-builtin-types/api/restricted_current.txt b/appsearch/appsearch-builtin-types/api/restricted_current.txt
index 4f35050..24fdb54 100644
--- a/appsearch/appsearch-builtin-types/api/restricted_current.txt
+++ b/appsearch/appsearch-builtin-types/api/restricted_current.txt
@@ -31,7 +31,7 @@
field public static final int COMPUTING_DEVICE_UNKNOWN = 0; // 0x0
}
- public static final class Alarm.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class Alarm.Builder {
ctor public Alarm.Builder(androidx.appsearch.builtintypes.Alarm);
ctor public Alarm.Builder(String, String);
method public androidx.appsearch.builtintypes.Alarm.Builder addAlternateName(String);
@@ -39,6 +39,7 @@
method public androidx.appsearch.builtintypes.Alarm build();
method public androidx.appsearch.builtintypes.Alarm.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Alarm.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.Alarm.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.Alarm.Builder setBlackoutPeriodEndDate(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setBlackoutPeriodStartDate(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setComputingDevice(int);
@@ -53,6 +54,7 @@
method public androidx.appsearch.builtintypes.Alarm.Builder setMinute(@IntRange(from=0, to=59) int);
method public androidx.appsearch.builtintypes.Alarm.Builder setName(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setNextInstance(androidx.appsearch.builtintypes.AlarmInstance?);
+ method public androidx.appsearch.builtintypes.Alarm.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Alarm.Builder setPreviousInstance(androidx.appsearch.builtintypes.AlarmInstance?);
method public androidx.appsearch.builtintypes.Alarm.Builder setRingtone(String?);
method public androidx.appsearch.builtintypes.Alarm.Builder setShouldVibrate(boolean);
@@ -71,7 +73,7 @@
field public static final int STATUS_UNKNOWN = 0; // 0x0
}
- public static final class AlarmInstance.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class AlarmInstance.Builder {
ctor public AlarmInstance.Builder(androidx.appsearch.builtintypes.AlarmInstance);
ctor public AlarmInstance.Builder(String, String, String);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder addAlternateName(String);
@@ -79,12 +81,14 @@
method public androidx.appsearch.builtintypes.AlarmInstance build();
method public androidx.appsearch.builtintypes.AlarmInstance.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.AlarmInstance.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.AlarmInstance.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setDocumentScore(int);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setDocumentTtlMillis(long);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setImage(String?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.AlarmInstance.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setSnoozeDurationMillis(long);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setStatus(int);
method public androidx.appsearch.builtintypes.AlarmInstance.Builder setUrl(String?);
@@ -97,7 +101,7 @@
method public java.util.List<java.lang.String!> getTelephones();
}
- public static final class ContactPoint.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class ContactPoint.Builder {
ctor public ContactPoint.Builder(androidx.appsearch.builtintypes.ContactPoint);
ctor public ContactPoint.Builder(String, String, String);
method public androidx.appsearch.builtintypes.ContactPoint.Builder addAlternateName(String);
@@ -106,6 +110,7 @@
method public androidx.appsearch.builtintypes.ContactPoint.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.ContactPoint.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.ContactPoint.Builder setAddresses(java.util.List<java.lang.String!>);
+ method public androidx.appsearch.builtintypes.ContactPoint.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setDocumentScore(int);
@@ -113,6 +118,7 @@
method public androidx.appsearch.builtintypes.ContactPoint.Builder setEmails(java.util.List<java.lang.String!>);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setImage(String?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.ContactPoint.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setTelephones(java.util.List<java.lang.String!>);
method public androidx.appsearch.builtintypes.ContactPoint.Builder setUrl(String?);
}
@@ -134,12 +140,14 @@
method public androidx.appsearch.builtintypes.ImageObject build();
method public androidx.appsearch.builtintypes.ImageObject.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.ImageObject.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.ImageObject.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.ImageObject.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setDocumentScore(int);
method public androidx.appsearch.builtintypes.ImageObject.Builder setDocumentTtlMillis(long);
method public androidx.appsearch.builtintypes.ImageObject.Builder setImage(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.ImageObject.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setSha256(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setThumbnailSha256(String?);
method public androidx.appsearch.builtintypes.ImageObject.Builder setUrl(String?);
@@ -180,6 +188,7 @@
method public androidx.appsearch.builtintypes.Person.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.Person.Builder setAdditionalNames(java.util.List<androidx.appsearch.builtintypes.Person.AdditionalName!>);
method public androidx.appsearch.builtintypes.Person.Builder setAffiliations(java.util.List<java.lang.String!>);
+ method public androidx.appsearch.builtintypes.Person.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.Person.Builder setBot(boolean);
method public androidx.appsearch.builtintypes.Person.Builder setContactPoints(java.util.List<androidx.appsearch.builtintypes.ContactPoint!>);
method public androidx.appsearch.builtintypes.Person.Builder setCreationTimestampMillis(long);
@@ -195,6 +204,7 @@
method public androidx.appsearch.builtintypes.Person.Builder setMiddleName(String);
method public androidx.appsearch.builtintypes.Person.Builder setName(String?);
method public androidx.appsearch.builtintypes.Person.Builder setNotes(java.util.List<java.lang.String!>);
+ method public androidx.appsearch.builtintypes.Person.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Person.Builder setRelations(java.util.List<java.lang.String!>);
method public androidx.appsearch.builtintypes.Person.Builder setUrl(String?);
}
@@ -238,6 +248,7 @@
method public androidx.appsearch.builtintypes.Stopwatch.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Stopwatch.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.Stopwatch.Builder setAccumulatedDurationMillis(long);
+ method public androidx.appsearch.builtintypes.Stopwatch.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public androidx.appsearch.builtintypes.Stopwatch.Builder setBaseTimeMillis(android.content.Context, long, long);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setBaseTimeMillis(long, long, int);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setCreationTimestampMillis(long);
@@ -247,6 +258,7 @@
method public androidx.appsearch.builtintypes.Stopwatch.Builder setImage(String?);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setLaps(java.util.List<androidx.appsearch.builtintypes.StopwatchLap!>);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.Stopwatch.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setStatus(int);
method public androidx.appsearch.builtintypes.Stopwatch.Builder setUrl(String?);
}
@@ -257,7 +269,7 @@
method public int getLapNumber();
}
- public static final class StopwatchLap.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class StopwatchLap.Builder {
ctor public StopwatchLap.Builder(androidx.appsearch.builtintypes.StopwatchLap);
ctor public StopwatchLap.Builder(String, String);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder addAlternateName(String);
@@ -266,6 +278,7 @@
method public androidx.appsearch.builtintypes.StopwatchLap.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.StopwatchLap.Builder clearPotentialActions();
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setAccumulatedLapDurationMillis(long);
+ method public androidx.appsearch.builtintypes.StopwatchLap.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setDocumentScore(int);
@@ -274,6 +287,7 @@
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setLapDurationMillis(long);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setLapNumber(int);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.StopwatchLap.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.StopwatchLap.Builder setUrl(String?);
}
@@ -291,7 +305,7 @@
method public String? getUrl();
}
- public static final class Thing.Builder {
+ @androidx.appsearch.annotation.Document.BuilderProducer public static final class Thing.Builder {
ctor public Thing.Builder(androidx.appsearch.builtintypes.Thing);
ctor public Thing.Builder(String, String);
method public androidx.appsearch.builtintypes.Thing.Builder addAlternateName(String);
@@ -299,12 +313,14 @@
method public androidx.appsearch.builtintypes.Thing build();
method public androidx.appsearch.builtintypes.Thing.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Thing.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.Thing.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method public androidx.appsearch.builtintypes.Thing.Builder setCreationTimestampMillis(long);
method public androidx.appsearch.builtintypes.Thing.Builder setDescription(String?);
method public androidx.appsearch.builtintypes.Thing.Builder setDocumentScore(int);
method public androidx.appsearch.builtintypes.Thing.Builder setDocumentTtlMillis(long);
method public androidx.appsearch.builtintypes.Thing.Builder setImage(String?);
method public androidx.appsearch.builtintypes.Thing.Builder setName(String?);
+ method public androidx.appsearch.builtintypes.Thing.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Thing.Builder setUrl(String?);
}
@@ -338,6 +354,7 @@
method public androidx.appsearch.builtintypes.Timer build();
method public androidx.appsearch.builtintypes.Timer.Builder clearAlternateNames();
method public androidx.appsearch.builtintypes.Timer.Builder clearPotentialActions();
+ method public androidx.appsearch.builtintypes.Timer.Builder setAlternateNames(java.util.List<java.lang.String!>?);
method @RequiresApi(api=android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) public androidx.appsearch.builtintypes.Timer.Builder setBaseTimeMillis(android.content.Context, long, long);
method public androidx.appsearch.builtintypes.Timer.Builder setBaseTimeMillis(long, long, int);
method public androidx.appsearch.builtintypes.Timer.Builder setCreationTimestampMillis(long);
@@ -348,6 +365,7 @@
method public androidx.appsearch.builtintypes.Timer.Builder setImage(String?);
method public androidx.appsearch.builtintypes.Timer.Builder setName(String?);
method public androidx.appsearch.builtintypes.Timer.Builder setOriginalDurationMillis(long);
+ method public androidx.appsearch.builtintypes.Timer.Builder setPotentialActions(java.util.List<androidx.appsearch.builtintypes.PotentialAction!>?);
method public androidx.appsearch.builtintypes.Timer.Builder setRemainingDurationMillis(long);
method public androidx.appsearch.builtintypes.Timer.Builder setRingtone(String?);
method public androidx.appsearch.builtintypes.Timer.Builder setShouldVibrate(boolean);
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmInstanceTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmInstanceTest.java
index 3e1036f..3d455ac 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmInstanceTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmInstanceTest.java
@@ -136,5 +136,10 @@
.isEqualTo(AlarmInstance.STATUS_SCHEDULED);
assertThat(genericDocument.getPropertyLong("snoozeDurationMillis"))
.isEqualTo(10000);
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ genericDocument.toDocumentClass(AlarmInstance.class));
+ assertThat(newGenericDocument).isEqualTo(genericDocument);
}
}
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmTest.java
index 5becd28..23a2776 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/AlarmTest.java
@@ -214,6 +214,11 @@
.isEqualTo(GenericDocument.fromDocumentClass(alarmInstance2));
assertThat(genericDocument.getPropertyLong("computingDevice"))
.isEqualTo(Alarm.COMPUTING_DEVICE_SMART_WATCH);
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ genericDocument.toDocumentClass(Alarm.class));
+ assertThat(newGenericDocument).isEqualTo(genericDocument);
}
@Test
@@ -245,5 +250,10 @@
assertThat(alarm.getDaysOfWeek()).isNull();
assertThat(alarmGenericDocument.getPropertyLongArray("daysOfWeek")).isNull();
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ alarmGenericDocument.toDocumentClass(Alarm.class));
+ assertThat(newGenericDocument).isEqualTo(alarmGenericDocument);
}
}
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ContactPointTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ContactPointTest.java
index 0a3b26d..fa00ed1 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ContactPointTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ContactPointTest.java
@@ -244,5 +244,10 @@
assertThat(doc.getPropertyStringArray("email")).asList().isEqualTo(emails);
assertThat(doc.getPropertyStringArray("address")).asList().isEqualTo(addresses);
assertThat(doc.getPropertyStringArray("telephone")).asList().isEqualTo(telephones);
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newDoc = GenericDocument.fromDocumentClass(
+ doc.toDocumentClass(ContactPoint.class));
+ assertThat(newDoc).isEqualTo(doc);
}
}
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/PersonTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/PersonTest.java
index 33f7330..625d031 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/PersonTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/PersonTest.java
@@ -560,6 +560,11 @@
assertThat(contactPointDocs.length).isEqualTo(contactPoints.size());
assertThat(contactPointDocs[0].getId()).isEqualTo("id1");
assertThat(contactPointDocs[1].getId()).isEqualTo("id2");
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ doc.toDocumentClass(Person.class));
+ assertThat(newGenericDocument).isEqualTo(doc);
}
@Test
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchLapTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchLapTest.java
index d2ea8b8..633833b 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchLapTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchLapTest.java
@@ -135,5 +135,10 @@
assertThat(genericDocument.getPropertyLong("lapDurationMillis")).isEqualTo(100);
assertThat(genericDocument.getPropertyLong("accumulatedLapDurationMillis"))
.isEqualTo(1100);
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ genericDocument.toDocumentClass(StopwatchLap.class));
+ assertThat(newGenericDocument).isEqualTo(genericDocument);
}
}
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchTest.java
index 2a75e0e..3fef500 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/StopwatchTest.java
@@ -192,6 +192,11 @@
.isEqualTo(1100);
assertThat(genericDocument.getPropertyDocumentArray("laps")).asList().containsExactly(
GenericDocument.fromDocumentClass(lap1), GenericDocument.fromDocumentClass(lap2));
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ genericDocument.toDocumentClass(Stopwatch.class));
+ assertThat(newGenericDocument).isEqualTo(genericDocument);
}
@Test
@@ -202,5 +207,10 @@
GenericDocument genericDocument = GenericDocument.fromDocumentClass(stopwatch);
assertThat(genericDocument.getPropertyDocumentArray("laps")).asList().isEmpty();
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ genericDocument.toDocumentClass(Stopwatch.class));
+ assertThat(newGenericDocument).isEqualTo(genericDocument);
}
}
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ThingTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ThingTest.java
index 92198a9..2663f95 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ThingTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/ThingTest.java
@@ -289,5 +289,13 @@
.isEqualTo("Make a phone call");
assertThat(document.getPropertyString("potentialActions[0].uri"))
.isEqualTo("package://call");
+
+ // Test that toDocumentClass doesn't lose information.
+ // Reset potentialActions to empty because its document class does not maintain the meta
+ // field creationTimestampMillis.
+ document = document.toBuilder().setPropertyDocument("potentialActions").build();
+ GenericDocument newDocument = GenericDocument.fromDocumentClass(
+ document.toDocumentClass(Thing.class));
+ assertThat(newDocument).isEqualTo(document);
}
}
diff --git a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/TimerTest.java b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/TimerTest.java
index 4f8bda2..e8e8016 100644
--- a/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/TimerTest.java
+++ b/appsearch/appsearch-builtin-types/src/androidTest/java/androidx/appsearch/builtintypes/TimerTest.java
@@ -182,5 +182,10 @@
assertThat(genericDocument.getPropertyLong("baseTimeMillisInElapsedRealtime"))
.isEqualTo(700);
assertThat(genericDocument.getPropertyLong("bootCount")).isEqualTo(1);
+
+ // Test that toDocumentClass doesn't lose information.
+ GenericDocument newGenericDocument = GenericDocument.fromDocumentClass(
+ genericDocument.toDocumentClass(Timer.class));
+ assertThat(newGenericDocument).isEqualTo(genericDocument);
}
}
diff --git a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Alarm.java b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Alarm.java
index 56336cf..43fb786 100644
--- a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Alarm.java
+++ b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Alarm.java
@@ -224,6 +224,7 @@
}
/** Builder for {@link Alarm}. */
+ @Document.BuilderProducer
public static final class Builder extends BuilderImpl<Builder> {
/**
* Constructor for {@link Alarm.Builder}.
diff --git a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/AlarmInstance.java b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/AlarmInstance.java
index 8559735..540a292 100644
--- a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/AlarmInstance.java
+++ b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/AlarmInstance.java
@@ -117,6 +117,7 @@
}
/** Builder for {@link AlarmInstance}. */
+ @Document.BuilderProducer
public static final class Builder extends BuilderImpl<Builder> {
/**
* Constructor for {@link AlarmInstance.Builder}.
diff --git a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/ContactPoint.java b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/ContactPoint.java
index 739e5a6..50e3a4a 100644
--- a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/ContactPoint.java
+++ b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/ContactPoint.java
@@ -102,6 +102,7 @@
}
/** Builder for {@link ContactPoint}. */
+ @Document.BuilderProducer
public static final class Builder extends BuilderImpl<Builder> {
/**
* Constructor for {@link ContactPoint.Builder}.
diff --git a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/StopwatchLap.java b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/StopwatchLap.java
index f5b979a..1b8cda4 100644
--- a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/StopwatchLap.java
+++ b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/StopwatchLap.java
@@ -76,6 +76,7 @@
}
/** Builder for {@link StopwatchLap}. */
+ @Document.BuilderProducer
public static final class Builder extends BuilderImpl<Builder> {
/**
* Constructor for {@link StopwatchLap.Builder}.
diff --git a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Thing.java b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Thing.java
index 954e949..cbcef7c 100644
--- a/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Thing.java
+++ b/appsearch/appsearch-builtin-types/src/main/java/androidx/appsearch/builtintypes/Thing.java
@@ -172,6 +172,7 @@
}
/** Builder for {@link Thing}. */
+ @Document.BuilderProducer
public static final class Builder extends BuilderImpl<Builder> {
/** Constructs {@link Thing.Builder} with given {@code namespace} and {@code id} */
public Builder(@NonNull String namespace, @NonNull String id) {
@@ -295,6 +296,18 @@
return (T) this;
}
+ /** Sets a list of aliases for the item. */
+ @NonNull
+ public T setAlternateNames(@Nullable List<String> alternateNames) {
+ resetIfBuilt();
+ if (alternateNames != null) {
+ mAlternateNames = new ArrayList<>(alternateNames);
+ } else {
+ clearAlternateNames();
+ }
+ return (T) this;
+ }
+
/** Clears the aliases, if any, for the item. */
@NonNull
public T clearAlternateNames() {
@@ -350,6 +363,18 @@
return (T) this;
}
+ /** Sets a list of potential actions for this document. */
+ @NonNull
+ public T setPotentialActions(@Nullable List<PotentialAction> newPotentialActions) {
+ resetIfBuilt();
+ if (newPotentialActions != null) {
+ mPotentialActions = new ArrayList<>(newPotentialActions);
+ } else {
+ clearPotentialActions();
+ }
+ return (T) this;
+ }
+
/**
* Clear all the potential actions for this document.
*/
diff --git a/appsearch/appsearch/api/current.txt b/appsearch/appsearch/api/current.txt
index 77b9381..96049d0 100644
--- a/appsearch/appsearch/api/current.txt
+++ b/appsearch/appsearch/api/current.txt
@@ -11,7 +11,7 @@
method public abstract boolean required() default false;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public static @interface Document.BuilderProducer {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) public static @interface Document.BuilderProducer {
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BytesProperty {
@@ -31,12 +31,6 @@
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DoubleProperty {
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.DoubleProperty.DefaultSerializer.class;
- }
-
- public static final class Document.DoubleProperty.DefaultSerializer {
- method public static double deserialize(double);
- method public static double serialize(double);
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Id {
@@ -46,12 +40,13 @@
method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_NONE;
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
+ method public abstract Class<? extends androidx.appsearch.app.LongSerializer<?>> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
}
- public static final class Document.LongProperty.DefaultSerializer {
- method public static long deserialize(long);
- method public static long serialize(long);
+ public static final class Document.LongProperty.DefaultSerializer implements androidx.appsearch.app.LongSerializer<java.lang.Long> {
+ ctor public Document.LongProperty.DefaultSerializer();
+ method public Long deserialize(long);
+ method public long serialize(Long);
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Namespace {
@@ -65,13 +60,14 @@
method public abstract int joinableValueType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE;
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
+ method public abstract Class<? extends androidx.appsearch.app.StringSerializer<?>> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
}
- public static final class Document.StringProperty.DefaultSerializer {
- method public static String deserialize(String);
- method public static String serialize(String);
+ public static final class Document.StringProperty.DefaultSerializer implements androidx.appsearch.app.StringSerializer<java.lang.String> {
+ ctor public Document.StringProperty.DefaultSerializer();
+ method public String deserialize(String);
+ method public String serialize(String);
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.TtlMillis {
@@ -380,6 +376,11 @@
method public androidx.appsearch.app.JoinSpec.Builder setNestedSearch(String, androidx.appsearch.app.SearchSpec);
}
+ public interface LongSerializer<T> {
+ method public T? deserialize(long);
+ method public long serialize(T);
+ }
+
public abstract class Migrator {
ctor public Migrator();
method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onDowngrade(int, int, androidx.appsearch.app.GenericDocument);
@@ -701,6 +702,11 @@
method public androidx.appsearch.app.StorageInfo.Builder setSizeBytes(long);
}
+ public interface StringSerializer<T> {
+ method public T? deserialize(String);
+ method public String serialize(T);
+ }
+
}
package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/api/restricted_current.txt b/appsearch/appsearch/api/restricted_current.txt
index 77b9381..96049d0 100644
--- a/appsearch/appsearch/api/restricted_current.txt
+++ b/appsearch/appsearch/api/restricted_current.txt
@@ -11,7 +11,7 @@
method public abstract boolean required() default false;
}
- @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public static @interface Document.BuilderProducer {
+ @java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) public static @interface Document.BuilderProducer {
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.BytesProperty {
@@ -31,12 +31,6 @@
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.DoubleProperty {
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.DoubleProperty.DefaultSerializer.class;
- }
-
- public static final class Document.DoubleProperty.DefaultSerializer {
- method public static double deserialize(double);
- method public static double serialize(double);
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Id {
@@ -46,12 +40,13 @@
method public abstract int indexingType() default androidx.appsearch.app.AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_NONE;
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
+ method public abstract Class<? extends androidx.appsearch.app.LongSerializer<?>> serializer() default androidx.appsearch.annotation.Document.LongProperty.DefaultSerializer.class;
}
- public static final class Document.LongProperty.DefaultSerializer {
- method public static long deserialize(long);
- method public static long serialize(long);
+ public static final class Document.LongProperty.DefaultSerializer implements androidx.appsearch.app.LongSerializer<java.lang.Long> {
+ ctor public Document.LongProperty.DefaultSerializer();
+ method public Long deserialize(long);
+ method public long serialize(Long);
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.Namespace {
@@ -65,13 +60,14 @@
method public abstract int joinableValueType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.JOINABLE_VALUE_TYPE_NONE;
method public abstract String name() default "";
method public abstract boolean required() default false;
- method public abstract Class<?> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
+ method public abstract Class<? extends androidx.appsearch.app.StringSerializer<?>> serializer() default androidx.appsearch.annotation.Document.StringProperty.DefaultSerializer.class;
method public abstract int tokenizerType() default androidx.appsearch.app.AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN;
}
- public static final class Document.StringProperty.DefaultSerializer {
- method public static String deserialize(String);
- method public static String serialize(String);
+ public static final class Document.StringProperty.DefaultSerializer implements androidx.appsearch.app.StringSerializer<java.lang.String> {
+ ctor public Document.StringProperty.DefaultSerializer();
+ method public String deserialize(String);
+ method public String serialize(String);
}
@java.lang.annotation.Documented @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public static @interface Document.TtlMillis {
@@ -380,6 +376,11 @@
method public androidx.appsearch.app.JoinSpec.Builder setNestedSearch(String, androidx.appsearch.app.SearchSpec);
}
+ public interface LongSerializer<T> {
+ method public T? deserialize(long);
+ method public long serialize(T);
+ }
+
public abstract class Migrator {
ctor public Migrator();
method @WorkerThread public abstract androidx.appsearch.app.GenericDocument onDowngrade(int, int, androidx.appsearch.app.GenericDocument);
@@ -701,6 +702,11 @@
method public androidx.appsearch.app.StorageInfo.Builder setSizeBytes(long);
}
+ public interface StringSerializer<T> {
+ method public T? deserialize(String);
+ method public String serialize(T);
+ }
+
}
package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
index fb0160f..75051c2 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTestBase.java
@@ -1130,6 +1130,112 @@
assertThat(newOrganization.getOrganizationDescription()).isEqualTo("organization_dec");
}
+ @Document(name = "Person", parent = InterfaceRoot.class)
+ interface Person extends InterfaceRoot {
+ @Document.StringProperty
+ String getFirstName();
+
+ @Document.StringProperty
+ String getLastName();
+
+ @Document.BuilderProducer
+ class Builder {
+ String mId;
+ String mNamespace;
+ long mCreationTimestamp;
+ String mFirstName;
+ String mLastName;
+
+ Builder(String id, String namespace) {
+ mId = id;
+ mNamespace = namespace;
+ }
+
+ public Person build() {
+ return new PersonImpl(mId, mNamespace, mCreationTimestamp, mFirstName, mLastName);
+ }
+
+ public Builder setCreationTimestamp(long creationTimestamp) {
+ mCreationTimestamp = creationTimestamp;
+ return this;
+ }
+
+ public Builder setFirstName(String firstName) {
+ mFirstName = firstName;
+ return this;
+ }
+
+ // Void return type should work.
+ public void setLastName(String lastName) {
+ mLastName = lastName;
+ }
+ }
+ }
+
+ static class PersonImpl implements Person {
+ String mId;
+ String mNamespace;
+ long mCreationTimestamp;
+ String mFirstName;
+ String mLastName;
+
+ PersonImpl(String id, String namespace, long creationTimestamp, String firstName,
+ String lastName) {
+ mId = id;
+ mNamespace = namespace;
+ mCreationTimestamp = creationTimestamp;
+ mFirstName = firstName;
+ mLastName = lastName;
+ }
+
+ public String getId() {
+ return mId;
+ }
+
+ public String getNamespace() {
+ return mNamespace;
+ }
+
+ public long getCreationTimestamp() {
+ return mCreationTimestamp;
+ }
+
+ public String getFirstName() {
+ return mFirstName;
+ }
+
+ public String getLastName() {
+ return mLastName;
+ }
+ }
+
+ @Test
+ public void testGenericDocumentConversion_BuilderConstructor() throws Exception {
+ // Create Person document
+ Person.Builder personBuilder = new Person.Builder("id", "namespace")
+ .setCreationTimestamp(3000)
+ .setFirstName("first");
+ personBuilder.setLastName("last");
+ Person person = personBuilder.build();
+
+ // Test the conversion from person to GenericDocument
+ GenericDocument genericDocument = GenericDocument.fromDocumentClass(person);
+ assertThat(genericDocument.getId()).isEqualTo("id");
+ assertThat(genericDocument.getNamespace()).isEqualTo("namespace");
+ assertThat(genericDocument.getCreationTimestampMillis()).isEqualTo(3000);
+ assertThat(genericDocument.getSchemaType()).isEqualTo("Person");
+ assertThat(genericDocument.getPropertyString("firstName")).isEqualTo("first");
+ assertThat(genericDocument.getPropertyString("lastName")).isEqualTo("last");
+
+ // Test the conversion from GenericDocument to person
+ Person newPerson = genericDocument.toDocumentClass(Person.class);
+ assertThat(newPerson.getId()).isEqualTo("id");
+ assertThat(newPerson.getNamespace()).isEqualTo("namespace");
+ assertThat(newPerson.getCreationTimestamp()).isEqualTo(3000);
+ assertThat(newPerson.getFirstName()).isEqualTo("first");
+ assertThat(newPerson.getLastName()).isEqualTo("last");
+ }
+
@Test
public void testPolymorphismForInterface() throws Exception {
assumeTrue(mSession.getFeatures().isFeatureSupported(Features.SCHEMA_ADD_PARENT_TYPE));
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
index e4b390d..6b09339 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/annotation/Document.java
@@ -18,6 +18,8 @@
import androidx.annotation.NonNull;
import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.LongSerializer;
+import androidx.appsearch.app.StringSerializer;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@@ -259,18 +261,7 @@
* <p>Useful for representing properties using rich types that boil down to simple string
* values in the database.
*
- * <p>The referenced class must satisfy the following:
- *
- * <ol>
- * <li>
- * Have a static method called {@code serialize} that converts the property's Java
- * type to a {@link String}.
- * </li>
- * <li>
- * Have a static method called {@code deserialize} that converts a {@link String} to
- * the property's Java type or returns null if deserialization failed.
- * </li>
- * </ol>
+ * <p>The referenced class must have a public zero params constructor.
*
* <p>For example:
*
@@ -282,17 +273,21 @@
* @Document.StringProperty(serializer = SomeRichTypeSerializer.class)
* public SomeRichType getMyProperty();
*
- * public final class SomeRichTypeSerializer {
- * public static String serialize(SomeRichType instance) {...}
+ * public final class SomeRichTypeSerializer implements StringSerializer<SomeRichType> {
*
+ * @Override
+ * @NonNull
+ * public String serialize(@NonNull SomeRichType instance) {...}
+ *
+ * @Override
* @Nullable
- * public static SomeRichType deserialize(String string) {...}
+ * public SomeRichType deserialize(@NonNull String string) {...}
* }
* }
* }
* </pre>
*/
- Class<?> serializer() default DefaultSerializer.class;
+ Class<? extends StringSerializer<?>> serializer() default DefaultSerializer.class;
/**
* Configures whether this property must be specified for the document to be valid.
@@ -305,16 +300,16 @@
*/
boolean required() default false;
- final class DefaultSerializer {
- private DefaultSerializer() {}
-
+ final class DefaultSerializer implements StringSerializer<String> {
+ @Override
@NonNull
- public static String serialize(@NonNull String value) {
- return value;
+ public String serialize(@NonNull String instance) {
+ return instance;
}
+ @Override
@NonNull
- public static String deserialize(@NonNull String string) {
+ public String deserialize(@NonNull String string) {
return string;
}
}
@@ -387,22 +382,11 @@
* <p>Useful for representing properties using rich types that boil down to simple 64-bit
* integer values in the database.
*
- * <p>The referenced class must satisfy the following:
- *
- * <ol>
- * <li>
- * Have a static method called {@code serialize} that converts the property's Java
- * type to a {@link Long}.
- * </li>
- * <li>
- * Have a static method called {@code deserialize} that converts a {@link Long} to
- * the property's Java type or returns null if deserialization failed.
- * </li>
- * </ol>
+ * <p>The referenced class must have a public zero params constructor.
*
* <p>See {@link StringProperty#serializer()} for an example of a serializer.
*/
- Class<?> serializer() default DefaultSerializer.class;
+ Class<? extends LongSerializer<?>> serializer() default DefaultSerializer.class;
/**
* Configures whether this property must be specified for the document to be valid.
@@ -415,15 +399,17 @@
*/
boolean required() default false;
- final class DefaultSerializer {
- private DefaultSerializer() {}
-
- public static long serialize(long value) {
+ final class DefaultSerializer implements LongSerializer<Long> {
+ @Override
+ public long serialize(@NonNull @SuppressWarnings("AutoBoxing") Long value) {
return value;
}
- public static long deserialize(long l) {
- return l;
+ @Override
+ @NonNull
+ @SuppressWarnings("AutoBoxing")
+ public Long deserialize(long value) {
+ return value;
}
}
}
@@ -444,29 +430,6 @@
String name() default "";
/**
- * Configures how a property should be converted to and from a {@link Double}.
- *
- * <p>Useful for representing properties using rich types that boil down to simple
- * double-precision decimal values in the database.
- *
- * <p>The referenced class must satisfy the following:
- *
- * <ol>
- * <li>
- * Have a static method called {@code serialize} that converts the property's Java
- * type to a {@link Double}.
- * </li>
- * <li>
- * Have a static method called {@code deserialize} that converts a {@link Double} to
- * the property's Java type or returns null if deserialization failed.
- * </li>
- * </ol>
- *
- * <p>See {@link StringProperty#serializer()} for an example of a serializer.
- */
- Class<?> serializer() default DefaultSerializer.class;
-
- /**
* Configures whether this property must be specified for the document to be valid.
*
* <p>This attribute does not apply to properties of a repeated type (e.g. a list).
@@ -476,18 +439,6 @@
* this attribute to {@code true}.
*/
boolean required() default false;
-
- final class DefaultSerializer {
- private DefaultSerializer() {}
-
- public static double serialize(double value) {
- return value;
- }
-
- public static double deserialize(double d) {
- return d;
- }
- }
}
/** Configures a boolean member field of a class as a property known to AppSearch. */
@@ -539,15 +490,24 @@
}
/**
- * Marks a method as a builder producer.
+ * Marks a static method or a builder class directly as a builder producer. A builder class
+ * should contain a "build()" method to construct the AppSearch document object and setter
+ * methods to set field values.
*
- * <p>A builder producer is a static method that returns a builder, which contains a "build()"
- * method to construct the AppSearch document object and setter methods to set field values.
- * Once a builder producer is specified, AppSearch will be forced to use the builder pattern to
- * construct the document object.
+ * <p>When a static method is marked as a builder producer, the method should return a
+ * builder instance for AppSearch to construct the document object. When a builder class is
+ * marked as a builder producer directly, AppSearch will use the constructor of the builder
+ * class to create a builder instance.
+ *
+ * <p>The annotated static method or the constructor of the annotated builder class is allowed
+ * to accept parameters to set a part of field values. In this case, AppSearch will only use
+ * setters to set values for the remaining fields.
+ *
+ * <p>Once a builder producer is specified, AppSearch will be forced to use the builder
+ * pattern to construct the document object.
*/
@Documented
@Retention(RetentionPolicy.CLASS)
- @Target(ElementType.METHOD)
+ @Target({ElementType.METHOD, ElementType.TYPE})
@interface BuilderProducer {}
}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/LongSerializer.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/LongSerializer.java
new file mode 100644
index 0000000..7c597bc
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/LongSerializer.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Serializes some {@link T} to and from a long.
+ *
+ * @param <T> The custom type that can be serialized to a long.
+ */
+public interface LongSerializer<T> {
+ /**
+ * Serializes a {@link T} to a long.
+ */
+ long serialize(@NonNull T instance);
+
+ /**
+ * Deserializes a {@link T} from a long. Returns null if deserialization failed.
+ */
+ @Nullable
+ T deserialize(long value);
+}
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/StringSerializer.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StringSerializer.java
new file mode 100644
index 0000000..bdfa575
--- /dev/null
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/StringSerializer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.app;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * Serializes some {@link T} to and from a String.
+ *
+ * @param <T> The custom type that can be serialized to a String.
+ */
+public interface StringSerializer<T> {
+ /**
+ * Serializes a {@link T} to a String.
+ */
+ @NonNull
+ String serialize(@NonNull T instance);
+
+ /**
+ * Deserializes a {@link T} from a String. Returns null if deserialization failed.
+ */
+ @Nullable
+ T deserialize(@NonNull String string);
+}
diff --git a/appsearch/compiler/build.gradle b/appsearch/compiler/build.gradle
index cb9caf4..c37b877 100644
--- a/appsearch/compiler/build.gradle
+++ b/appsearch/compiler/build.gradle
@@ -31,6 +31,8 @@
implementation(libs.autoValueAnnotations)
implementation(libs.javapoet)
+ annotationProcessor(libs.autoValue)
+
// For testing, add in the compiled classes from appsearch to get access to annotations.
testImplementationAarAsJar(project(":appsearch:appsearch"))
testImplementation(libs.googleCompileTesting)
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
index 226156f..e9df0dc 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/DocumentModel.java
@@ -109,7 +109,7 @@
private ExecutableElement mChosenCreationMethod = null;
private List<String> mChosenCreationMethodParams = null;
private TypeElement mBuilderClass = null;
- private ExecutableElement mBuilderProducer = null;
+ private Set<ExecutableElement> mBuilderProducers = new LinkedHashSet<>();
private DocumentModel(
@NonNull ProcessingEnvironment env,
@@ -141,17 +141,13 @@
/**
* Scans all the elements in typeElement to find a builder producer. If found, set
- * mBuilderProducer and mBuilderClass to the builder producer and the return type
+ * mBuilderProducers and mBuilderClass to the builder producer candidates and the builder class
* respectively.
*
* @throws ProcessingException if there are more than one elements annotated with
* {@code @Document.BuilderProducer}, or if the builder producer element is not a visible static
- * method.
+ * method or a class.
*/
- // TODO(b/285149515): Other than using a static method, we should support builder constructor
- // as well to create builder instances, as this is the right pattern compliant with Android
- // API guidelines.
- // go/android-api-guidelines#builder-constructor
private void extractBuilderProducer(TypeElement typeElement)
throws ProcessingException {
for (Element child : typeElement.getEnclosedElements()) {
@@ -166,25 +162,36 @@
if (!isAnnotated) {
continue;
}
- if (child.getKind() != ElementKind.METHOD) {
- // Since @Document.BuilderProducer is configured with @Target(ElementType.METHOD),
- // it's not possible to reach here.
- throw new ProcessingException("Builder producer must be a method", child);
+ if (child.getKind() != ElementKind.METHOD && child.getKind() != ElementKind.CLASS) {
+ // Since @Document.BuilderProducer is configured with
+ // @Target({ElementType.METHOD, ElementType.TYPE}), it's not possible to reach here.
+ throw new ProcessingException("Builder producer must be a method or a class",
+ child);
}
- ExecutableElement method = (ExecutableElement) child;
- Set<Modifier> methodModifiers = method.getModifiers();
+ if (mBuilderClass != null) {
+ throw new ProcessingException("Found duplicated builder producer", typeElement);
+ }
+ Set<Modifier> methodModifiers = child.getModifiers();
if (!methodModifiers.contains(Modifier.STATIC)) {
- throw new ProcessingException("Builder producer must be static", method);
+ throw new ProcessingException("Builder producer must be static", child);
}
if (methodModifiers.contains(Modifier.PRIVATE)) {
- throw new ProcessingException("Builder producer cannot be private", method);
+ throw new ProcessingException("Builder producer cannot be private", child);
}
-
- if (mBuilderProducer == null) {
- mBuilderProducer = method;
- mBuilderClass = (TypeElement) mTypeUtil.asElement(mBuilderProducer.getReturnType());
+ if (child.getKind() == ElementKind.METHOD) {
+ ExecutableElement method = (ExecutableElement) child;
+ mBuilderProducers.add(method);
+ mBuilderClass = (TypeElement) mTypeUtil.asElement(method.getReturnType());
} else {
- throw new ProcessingException("Found duplicated builder producer", method);
+ // child is a class, so extract all of its constructors as builder producer
+ // candidates. The validity of the constructor will be checked later when we
+ // choose the right creation method.
+ mBuilderClass = (TypeElement) child;
+ for (Element builderProducer : mBuilderClass.getEnclosedElements()) {
+ if (builderProducer.getKind() == ElementKind.CONSTRUCTOR) {
+ mBuilderProducers.add((ExecutableElement) builderProducer);
+ }
+ }
}
}
}
@@ -194,8 +201,8 @@
extractBuilderProducer(typeElement);
// If a builder producer is provided, then only the builder can be used as a creation
// method.
- if (mBuilderProducer != null) {
- return Collections.singleton(mBuilderProducer);
+ if (mBuilderClass != null) {
+ return Collections.unmodifiableSet(mBuilderProducers);
}
Set<ExecutableElement> creationMethods = new LinkedHashSet<>();
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
index f63c8b8..e0e0b56 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
@@ -92,17 +92,22 @@
// Create an instance of the document class via the chosen create method.
TypeElement builderClass = mModel.getBuilderClass();
- if (mModel.getBuilderClass() != null) {
+ String target;
+ TypeName targetClassType;
+ if (builderClass != null) {
+ target = "builder";
+ targetClassType = TypeName.get(builderClass.asType());
+ } else {
+ target = "document";
+ targetClassType = classType;
+ }
+ if (mModel.getChosenCreationMethod().getKind() == ElementKind.CONSTRUCTOR) {
methodBuilder.addStatement(
- "$T builder = $T.$L($L)", builderClass, classType,
- mModel.getChosenCreationMethod().getSimpleName().toString(),
+ "$T $N = new $T($L)", targetClassType, target, targetClassType,
getCreationMethodParams());
- } else if (mModel.getChosenCreationMethod().getKind() == ElementKind.CONSTRUCTOR) {
- methodBuilder.addStatement(
- "$T document = new $T($L)", classType, classType, getCreationMethodParams());
} else {
methodBuilder.addStatement(
- "$T document = $T.$L($L)", classType, classType,
+ "$T $N = $T.$L($L)", targetClassType, target, classType,
mModel.getChosenCreationMethod().getSimpleName().toString(),
getCreationMethodParams());
}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
index ad2e92e..bc30992 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
@@ -20,7 +20,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
-import androidx.annotation.VisibleForTesting;
import com.google.auto.value.AutoValue;
import com.squareup.javapoet.ClassName;
@@ -57,18 +56,18 @@
* @exportToFramework:hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class IntrospectionHelper {
- @VisibleForTesting
+public class IntrospectionHelper {
static final String GEN_CLASS_PREFIX = "$$__AppSearch__";
static final String APPSEARCH_PKG = "androidx.appsearch.app";
static final String APPSEARCH_EXCEPTION_PKG = "androidx.appsearch.exceptions";
static final String APPSEARCH_EXCEPTION_SIMPLE_NAME = "AppSearchException";
- static final String DOCUMENT_ANNOTATION_CLASS = "androidx.appsearch.annotation.Document";
+ public static final String DOCUMENT_ANNOTATION_CLASS = "androidx.appsearch.annotation.Document";
static final String ID_CLASS = "androidx.appsearch.annotation.Document.Id";
static final String NAMESPACE_CLASS = "androidx.appsearch.annotation.Document.Namespace";
static final String CREATION_TIMESTAMP_MILLIS_CLASS =
"androidx.appsearch.annotation.Document.CreationTimestampMillis";
- static final String TTL_MILLIS_CLASS = "androidx.appsearch.annotation.Document.TtlMillis";
+ static final String TTL_MILLIS_CLASS = "androidx.appsearch.annotation.Document"
+ + ".TtlMillis";
static final String SCORE_CLASS = "androidx.appsearch.annotation.Document.Score";
static final String BUILDER_PRODUCER_CLASS =
"androidx.appsearch.annotation.Document.BuilderProducer";
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BooleanPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BooleanPropertyAnnotation.java
new file mode 100644
index 0000000..0d84e17
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BooleanPropertyAnnotation.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.BooleanProperty} annotation.
+ */
+@AutoValue
+public abstract class BooleanPropertyAnnotation extends DataPropertyAnnotation {
+ public static final String SIMPLE_CLASS_NAME = "BooleanProperty";
+ public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+ public BooleanPropertyAnnotation() {
+ super(SIMPLE_CLASS_NAME);
+ }
+
+ /**
+ * @param defaultName The name to use for the annotated property in case the annotation
+ * params do not mention an explicit name.
+ */
+ @NonNull
+ static BooleanPropertyAnnotation parse(
+ @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+ String name = (String) annotationParams.get("name");
+ return new AutoValue_BooleanPropertyAnnotation(
+ name.isEmpty() ? defaultName : name, (boolean) annotationParams.get("required"));
+ }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BytesPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BytesPropertyAnnotation.java
new file mode 100644
index 0000000..35cc428
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/BytesPropertyAnnotation.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.BytesProperty} annotation.
+ */
+@AutoValue
+public abstract class BytesPropertyAnnotation extends DataPropertyAnnotation {
+ public static final String SIMPLE_CLASS_NAME = "BytesProperty";
+ public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+ public BytesPropertyAnnotation() {
+ super(SIMPLE_CLASS_NAME);
+ }
+
+ /**
+ * @param defaultName The name to use for the annotated property in case the annotation
+ * params do not mention an explicit name.
+ */
+ @NonNull
+ static BytesPropertyAnnotation parse(
+ @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+ String name = (String) annotationParams.get("name");
+ return new AutoValue_BytesPropertyAnnotation(
+ name.isEmpty() ? defaultName : name, (boolean) annotationParams.get("required"));
+ }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DataPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DataPropertyAnnotation.java
new file mode 100644
index 0000000..245072a
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DataPropertyAnnotation.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appsearch.compiler.IntrospectionHelper;
+
+import java.util.Map;
+
+import javax.lang.model.element.AnnotationMirror;
+
+/**
+ * An instance of an annotation for a data property e.g. {@code @Document.StringProperty}.
+ *
+ * <p>Is one of:
+ * <ul>
+ * <li>{@link StringPropertyAnnotation}</li>
+ * <li>{@link DocumentPropertyAnnotation}</li>
+ * <li>{@link LongPropertyAnnotation}</li>
+ * <li>{@link DoublePropertyAnnotation}</li>
+ * <li>{@link BooleanPropertyAnnotation}</li>
+ * <li>{@link BytesPropertyAnnotation}</li>
+ * </ul>
+ */
+public abstract class DataPropertyAnnotation implements PropertyAnnotation {
+ @NonNull
+ private final String mSimpleClassName;
+
+ DataPropertyAnnotation(@NonNull String simpleClassName) {
+ mSimpleClassName = simpleClassName;
+ }
+
+ /**
+ * Attempts to parse an {@link AnnotationMirror} into a {@link DataPropertyAnnotation}, or null.
+ *
+ * @param defaultName The name to use for the annotated property in case the annotation
+ * params do not mention an explicit name.
+ */
+ @Nullable
+ public static DataPropertyAnnotation tryParse(
+ @NonNull AnnotationMirror annotation,
+ @NonNull String defaultName,
+ @NonNull IntrospectionHelper helper) {
+ Map<String, Object> annotationParams = helper.getAnnotationParams(annotation);
+ String qualifiedClassName = annotation.getAnnotationType().toString();
+ switch (qualifiedClassName) {
+ case BooleanPropertyAnnotation.CLASS_NAME:
+ return BooleanPropertyAnnotation.parse(annotationParams, defaultName);
+ case BytesPropertyAnnotation.CLASS_NAME:
+ return BytesPropertyAnnotation.parse(annotationParams, defaultName);
+ case DocumentPropertyAnnotation.CLASS_NAME:
+ return DocumentPropertyAnnotation.parse(annotationParams, defaultName);
+ case DoublePropertyAnnotation.CLASS_NAME:
+ return DoublePropertyAnnotation.parse(annotationParams, defaultName);
+ case LongPropertyAnnotation.CLASS_NAME:
+ return LongPropertyAnnotation.parse(annotationParams, defaultName);
+ case StringPropertyAnnotation.CLASS_NAME:
+ return StringPropertyAnnotation.parse(annotationParams, defaultName);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * The serialized name for the property in the database.
+ */
+ @NonNull
+ public abstract String getName();
+
+ /**
+ * Denotes whether this property must be specified for the document to be valid.
+ */
+ public abstract boolean isRequired();
+
+ @NonNull
+ @Override
+ public final String getSimpleClassName() {
+ return mSimpleClassName;
+ }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DocumentPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DocumentPropertyAnnotation.java
new file mode 100644
index 0000000..53c2523
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DocumentPropertyAnnotation.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.DocumentProperty} annotation.
+ */
+@AutoValue
+public abstract class DocumentPropertyAnnotation extends DataPropertyAnnotation {
+ public static final String SIMPLE_CLASS_NAME = "DocumentProperty";
+ public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+ public DocumentPropertyAnnotation() {
+ super(SIMPLE_CLASS_NAME);
+ }
+
+ /**
+ * @param defaultName The name to use for the annotated property in case the annotation
+ * params do not mention an explicit name.
+ */
+ @NonNull
+ static DocumentPropertyAnnotation parse(
+ @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+ String name = (String) annotationParams.get("name");
+ return new AutoValue_DocumentPropertyAnnotation(
+ name.isEmpty() ? defaultName : name,
+ (boolean) annotationParams.get("required"),
+ (boolean) annotationParams.get("indexNestedProperties"));
+ }
+
+ /**
+ * Specifies whether fields in the nested document should be indexed.
+ */
+ public abstract boolean shouldIndexNestedProperties();
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DoublePropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DoublePropertyAnnotation.java
new file mode 100644
index 0000000..1a85e16
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/DoublePropertyAnnotation.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.DoubleProperty} annotation.
+ */
+@AutoValue
+public abstract class DoublePropertyAnnotation extends DataPropertyAnnotation {
+ public static final String SIMPLE_CLASS_NAME = "DoubleProperty";
+ public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+ public DoublePropertyAnnotation() {
+ super(SIMPLE_CLASS_NAME);
+ }
+
+ /**
+ * @param defaultName The name to use for the annotated property in case the annotation
+ * params do not mention an explicit name.
+ */
+ @NonNull
+ static DoublePropertyAnnotation parse(
+ @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+ String name = (String) annotationParams.get("name");
+ return new AutoValue_DoublePropertyAnnotation(
+ name.isEmpty() ? defaultName : name, (boolean) annotationParams.get("required"));
+ }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/LongPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/LongPropertyAnnotation.java
new file mode 100644
index 0000000..2f66b04
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/LongPropertyAnnotation.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.LongProperty} annotation.
+ */
+@AutoValue
+public abstract class LongPropertyAnnotation extends DataPropertyAnnotation {
+ public static final String SIMPLE_CLASS_NAME = "LongProperty";
+ public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+ public LongPropertyAnnotation() {
+ super(SIMPLE_CLASS_NAME);
+ }
+
+ /**
+ * @param defaultName The name to use for the annotated property in case the annotation
+ * params do not mention an explicit name.
+ */
+ @NonNull
+ static LongPropertyAnnotation parse(
+ @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+ String name = (String) annotationParams.get("name");
+ return new AutoValue_LongPropertyAnnotation(
+ name.isEmpty() ? defaultName : name,
+ (boolean) annotationParams.get("required"),
+ (int) annotationParams.get("indexingType"));
+ }
+
+ /**
+ * Specifies how a property should be indexed.
+ */
+ public abstract int getIndexingType();
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/MetadataPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/MetadataPropertyAnnotation.java
new file mode 100644
index 0000000..9253048
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/MetadataPropertyAnnotation.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static java.util.Objects.requireNonNull;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Arrays;
+
+import javax.lang.model.element.AnnotationMirror;
+
+/**
+ * An annotation for a metadata property e.g. {@code @Document.Id}.
+ */
+public enum MetadataPropertyAnnotation implements PropertyAnnotation {
+ ID(/* simpleClassName= */"Id"),
+ NAMESPACE(/* simpleClassName= */"Namespace"),
+ CREATION_TIMESTAMP_MILLIS(/* simpleClassName= */"CreationTimestampMillis"),
+ TTL_MILLIS(/* simpleClassName= */"TtlMillis"),
+ SCORE(/* simpleClassName= */"Score");
+
+ /**
+ * Attempts to parse an {@link AnnotationMirror} into a {@link MetadataPropertyAnnotation},
+ * or null.
+ */
+ @Nullable
+ public static MetadataPropertyAnnotation tryParse(@NonNull AnnotationMirror annotation) {
+ String qualifiedClassName = annotation.getAnnotationType().toString();
+ return Arrays.stream(values())
+ .filter(val -> val.getQualifiedClassName().equals(qualifiedClassName))
+ .findFirst()
+ .orElse(null);
+ }
+
+ @NonNull
+ private final String mSimpleClassName;
+
+ MetadataPropertyAnnotation(@NonNull String simpleClassName) {
+ mSimpleClassName = requireNonNull(simpleClassName);
+ }
+
+ @Override
+ @NonNull
+ public String getSimpleClassName() {
+ return mSimpleClassName;
+ }
+}
+
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/PropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/PropertyAnnotation.java
new file mode 100644
index 0000000..41cf474
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/PropertyAnnotation.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+/**
+ * An instance of an AppSearch property annotation.
+ *
+ * <p>Is one of:
+ * <ul>
+ * <li>{@link MetadataPropertyAnnotation} e.g. {@code @Document.Id}</li>
+ * <li>{@link DataPropertyAnnotation} e.g. {@code @Document.StringProperty}</li>
+ * </ul>
+ */
+public interface PropertyAnnotation {
+ /**
+ * The annotation class' simple name.
+ *
+ * <p>For example, {@code StringProperty} for a {@link StringPropertyAnnotation}.
+ */
+ @NonNull
+ String getSimpleClassName();
+
+ /**
+ * The annotation class' qualified name
+ *
+ * <p>{@code androidx.appsearch.annotation.Document.StringProperty} for a
+ * {@link StringPropertyAnnotation}.
+ */
+ @NonNull
+ default String getQualifiedClassName() {
+ return DOCUMENT_ANNOTATION_CLASS + "." + getSimpleClassName();
+ }
+}
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/StringPropertyAnnotation.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/StringPropertyAnnotation.java
new file mode 100644
index 0000000..ddcdf8e
--- /dev/null
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/annotationwrapper/StringPropertyAnnotation.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appsearch.compiler.annotationwrapper;
+
+import static androidx.appsearch.compiler.IntrospectionHelper.DOCUMENT_ANNOTATION_CLASS;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+import java.util.Map;
+
+/**
+ * An instance of the {@code @Document.StringProperty} annotation.
+ */
+@AutoValue
+public abstract class StringPropertyAnnotation extends DataPropertyAnnotation {
+ public static final String SIMPLE_CLASS_NAME = "StringProperty";
+ public static final String CLASS_NAME = DOCUMENT_ANNOTATION_CLASS + "." + SIMPLE_CLASS_NAME;
+
+ public StringPropertyAnnotation() {
+ super(SIMPLE_CLASS_NAME);
+ }
+
+ /**
+ * @param defaultName The name to use for the annotated property in case the annotation
+ * params do not mention an explicit name.
+ */
+ @NonNull
+ static StringPropertyAnnotation parse(
+ @NonNull Map<String, Object> annotationParams, @NonNull String defaultName) {
+ String name = (String) annotationParams.get("name");
+ return new AutoValue_StringPropertyAnnotation(
+ name.isEmpty() ? defaultName : name,
+ (boolean) annotationParams.get("required"),
+ (int) annotationParams.get("tokenizerType"),
+ (int) annotationParams.get("indexingType"),
+ (int) annotationParams.get("joinableValueType"));
+ }
+
+ /**
+ * Specifies how tokens should be extracted from this property.
+ */
+ public abstract int getTokenizerType();
+
+ /**
+ * Specifies how a property should be indexed.
+ */
+ public abstract int getIndexingType();
+
+ /**
+ * Specifies how a property should be processed so that the document can be joined.
+ */
+ public abstract int getJoinableValueType();
+}
diff --git a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
index 222f3aa..d10c4bb 100644
--- a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
+++ b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
@@ -2292,6 +2292,110 @@
}
@Test
+ public void testCreationByBuilderAnnotatingBuilderClass() throws Exception {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public interface Gift {\n"
+ + " @Document.Namespace public String getNamespace();\n"
+ + " @Document.Id public String getId();\n"
+ + " @Document.LongProperty public int getPrice();\n"
+ + " @Document.BuilderProducer\n"
+ + " class GiftBuilder {\n"
+ + " private String namespace;\n"
+ + " private String id;\n"
+ + " private int price;\n"
+ + " public GiftBuilder setNamespace(String namespace) {\n"
+ + " this.namespace = namespace;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public GiftBuilder setId(String id) {\n"
+ + " this.id = id;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public GiftBuilder setPrice(int price) {\n"
+ + " this.price = price;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public Gift build() {\n"
+ + " return new GiftImpl(this.id, this.namespace, this.price);\n"
+ + " }\n"
+ + " }\n"
+ + "}\n"
+ + "class GiftImpl implements Gift {\n"
+ + " public GiftImpl(String id, String namespace, int price) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " this.price = price;\n"
+ + " }\n"
+ + " private String namespace;\n"
+ + " private String id;\n"
+ + " private int price;\n"
+ + " public String getNamespace() { return namespace; }\n"
+ + " public String getId() { return id; }\n"
+ + " public int getPrice() { return price; }\n"
+ + "}\n");
+ assertThat(compilation).succeededWithoutWarnings();
+ checkResultContains("Gift.java",
+ "Gift.GiftBuilder builder = new Gift.GiftBuilder()");
+ checkResultContains("Gift.java", "builder.setNamespace(getNamespaceConv)");
+ checkResultContains("Gift.java", "builder.setId(getIdConv)");
+ checkResultContains("Gift.java", "builder.setPrice(getPriceConv)");
+ checkResultContains("Gift.java", "builder.build()");
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
+ public void testCreationByBuilderWithParameterAnnotatingBuilderClass() throws Exception {
+ Compilation compilation = compile(
+ "@Document\n"
+ + "public interface Gift {\n"
+ + " @Document.Namespace public String getNamespace();\n"
+ + " @Document.Id public String getId();\n"
+ + " @Document.LongProperty public int getPrice();\n"
+ + " @Document.BuilderProducer\n"
+ + " class GiftBuilder {\n"
+ + " private String namespace;\n"
+ + " private String id;\n"
+ + " private int price;\n"
+ + " public GiftBuilder(int price) {\n"
+ + " this.price = price;\n"
+ + " }\n"
+ + " public GiftBuilder setNamespace(String namespace) {\n"
+ + " this.namespace = namespace;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public GiftBuilder setId(String id) {\n"
+ + " this.id = id;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public Gift build() {\n"
+ + " return new GiftImpl(this.id, this.namespace, this.price);\n"
+ + " }\n"
+ + " }\n"
+ + "}\n"
+ + "class GiftImpl implements Gift {\n"
+ + " public GiftImpl(String id, String namespace, int price) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " this.price = price;\n"
+ + " }\n"
+ + " private String namespace;\n"
+ + " private String id;\n"
+ + " private int price;\n"
+ + " public String getNamespace() { return namespace; }\n"
+ + " public String getId() { return id; }\n"
+ + " public int getPrice() { return price; }\n"
+ + "}\n");
+ assertThat(compilation).succeededWithoutWarnings();
+ checkResultContains("Gift.java",
+ "Gift.GiftBuilder builder = new Gift.GiftBuilder(getPriceConv)");
+ checkResultContains("Gift.java", "builder.setNamespace(getNamespaceConv)");
+ checkResultContains("Gift.java", "builder.setId(getIdConv)");
+ checkResultContains("Gift.java", "builder.build()");
+ checkEqualsGolden("Gift.java");
+ }
+
+ @Test
public void testCreationByBuilderOnly() throws Exception {
// Once a builder producer is provided, AppSearch will only use the builder pattern, even
// if another creation method is available.
@@ -2421,7 +2525,7 @@
+ "}\n");
assertThat(compilation).hadErrorContaining("Found duplicated builder producer");
- // Builder producer must be static
+ // Builder producer method must be static
compilation = compile(
"@Document\n"
+ "public interface Gift {\n"
@@ -2458,7 +2562,36 @@
+ "}\n");
assertThat(compilation).hadErrorContaining("Builder producer must be static");
- // Builder producer cannot be private
+ // Builder producer class must be static
+ compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " public Gift(String id, String namespace) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " }\n"
+ + " @Document.Namespace public String namespace;\n"
+ + " @Document.Id public String id;\n"
+ + " @Document.BuilderProducer\n"
+ + " class Builder {\n"
+ + " private String namespace;\n"
+ + " private String id;\n"
+ + " public Builder setNamespace(String namespace) {\n"
+ + " this.namespace = namespace;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public Builder setId(String id) {\n"
+ + " this.id = id;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public Gift build() {\n"
+ + " return new Gift(this.id, this.namespace);\n"
+ + " }\n"
+ + " }\n"
+ + "}\n");
+ assertThat(compilation).hadErrorContaining("Builder producer must be static");
+
+ // Builder producer method cannot be private
compilation = compile(
"@Document\n"
+ "public interface Gift {\n"
@@ -2495,7 +2628,36 @@
+ "}\n");
assertThat(compilation).hadErrorContaining("Builder producer cannot be private");
- // Builder producer must be a method
+ // Builder producer class cannot be private
+ compilation = compile(
+ "@Document\n"
+ + "public class Gift {\n"
+ + " public Gift(String id, String namespace) {\n"
+ + " this.id = id;\n"
+ + " this.namespace = namespace;\n"
+ + " }\n"
+ + " @Document.Namespace public String namespace;\n"
+ + " @Document.Id public String id;\n"
+ + " @Document.BuilderProducer\n"
+ + " private static class Builder {\n"
+ + " private String namespace;\n"
+ + " private String id;\n"
+ + " public Builder setNamespace(String namespace) {\n"
+ + " this.namespace = namespace;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public Builder setId(String id) {\n"
+ + " this.id = id;\n"
+ + " return this;\n"
+ + " }\n"
+ + " public Gift build() {\n"
+ + " return new Gift(this.id, this.namespace);\n"
+ + " }\n"
+ + " }\n"
+ + "}\n");
+ assertThat(compilation).hadErrorContaining("Builder producer cannot be private");
+
+ // Builder producer must be a method or a class.
compilation = compile(
"@Document\n"
+ "public class Gift {\n"
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCreationByBuilderAnnotatingBuilderClass.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCreationByBuilderAnnotatingBuilderClass.JAVA
new file mode 100644
index 0000000..4144e12
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCreationByBuilderAnnotatingBuilderClass.JAVA
@@ -0,0 +1,57 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DocumentClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Class;
+import java.lang.Override;
+import java.lang.String;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public final class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
+
+ @Override
+ public String getSchemaName() {
+ return SCHEMA_NAME;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
+ }
+
+ @Override
+ public List<Class<?>> getDependencyDocumentClasses() throws AppSearchException {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(document.getNamespace(), document.getId(), SCHEMA_NAME);
+ builder.setPropertyLong("price", document.getPrice());
+ return builder.build();
+ }
+
+ @Override
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String getIdConv = genericDoc.getId();
+ String getNamespaceConv = genericDoc.getNamespace();
+ int getPriceConv = (int) genericDoc.getPropertyLong("price");
+ Gift.GiftBuilder builder = new Gift.GiftBuilder();
+ builder.setNamespace(getNamespaceConv);
+ builder.setId(getIdConv);
+ builder.setPrice(getPriceConv);
+ return builder.build();
+ }
+}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCreationByBuilderWithParameterAnnotatingBuilderClass.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCreationByBuilderWithParameterAnnotatingBuilderClass.JAVA
new file mode 100644
index 0000000..eb075fb
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCreationByBuilderWithParameterAnnotatingBuilderClass.JAVA
@@ -0,0 +1,56 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DocumentClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Class;
+import java.lang.Override;
+import java.lang.String;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.appsearch.compiler.AppSearchCompiler")
+public final class $$__AppSearch__Gift implements DocumentClassFactory<Gift> {
+ public static final String SCHEMA_NAME = "Gift";
+
+ @Override
+ public String getSchemaName() {
+ return SCHEMA_NAME;
+ }
+
+ @Override
+ public AppSearchSchema getSchema() throws AppSearchException {
+ return new AppSearchSchema.Builder(SCHEMA_NAME)
+ .addProperty(new AppSearchSchema.LongPropertyConfig.Builder("price")
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.LongPropertyConfig.INDEXING_TYPE_NONE)
+ .build())
+ .build();
+ }
+
+ @Override
+ public List<Class<?>> getDependencyDocumentClasses() throws AppSearchException {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public GenericDocument toGenericDocument(Gift document) throws AppSearchException {
+ GenericDocument.Builder<?> builder =
+ new GenericDocument.Builder<>(document.getNamespace(), document.getId(), SCHEMA_NAME);
+ builder.setPropertyLong("price", document.getPrice());
+ return builder.build();
+ }
+
+ @Override
+ public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+ String getIdConv = genericDoc.getId();
+ String getNamespaceConv = genericDoc.getNamespace();
+ int getPriceConv = (int) genericDoc.getPropertyLong("price");
+ Gift.GiftBuilder builder = new Gift.GiftBuilder(getPriceConv);
+ builder.setNamespace(getNamespaceConv);
+ builder.setId(getIdConv);
+ return builder.build();
+ }
+}
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
index 3ff0f4b..fe8a394 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
@@ -192,7 +192,10 @@
// Read the profile rules from the file collection that contains the profile artifacts from
// all the configurations for this variant and merge them in a single list.
val profileRules = baselineProfileFileCollection.files
- .readLines { FILENAME_MATCHER_BASELINE_PROFILE in it.name }
+ .readLines {
+ FILENAME_MATCHER_BASELINE_PROFILE in it.name ||
+ FILENAME_MATCHER_STARTUP_PROFILE in it.name
+ }
if (variantName.isPresent && profileRules.isEmpty()) {
logger.warn(
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
index 7f6b19aa..bd086a0 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
@@ -111,6 +111,10 @@
Fixtures.CLASS_1_METHOD_1,
Fixtures.CLASS_2,
Fixtures.CLASS_2_METHOD_1,
+ Fixtures.CLASS_3_METHOD_1,
+ Fixtures.CLASS_3,
+ Fixtures.CLASS_4_METHOD_1,
+ Fixtures.CLASS_4
)
assertThat(startupProfileFile("main").exists()).isFalse()
@@ -152,6 +156,10 @@
Fixtures.CLASS_1_METHOD_1,
Fixtures.CLASS_2,
Fixtures.CLASS_2_METHOD_1,
+ Fixtures.CLASS_3,
+ Fixtures.CLASS_3_METHOD_1,
+ Fixtures.CLASS_4,
+ Fixtures.CLASS_4_METHOD_1,
)
assertThat(readStartupProfileFileContent("release"))
@@ -239,12 +247,16 @@
.containsExactly(
Fixtures.CLASS_1,
Fixtures.CLASS_1_METHOD_1,
+ Fixtures.CLASS_3,
+ Fixtures.CLASS_3_METHOD_1,
)
assertThat(readBaselineProfileFileContent("paidRelease"))
.containsExactly(
Fixtures.CLASS_2,
Fixtures.CLASS_2_METHOD_1,
+ Fixtures.CLASS_4,
+ Fixtures.CLASS_4_METHOD_1,
)
}
diff --git a/benchmark/benchmark-common/api/1.2.0-beta03.txt b/benchmark/benchmark-common/api/1.2.0-beta03.txt
new file mode 100644
index 0000000..eb18450
--- /dev/null
+++ b/benchmark/benchmark-common/api/1.2.0-beta03.txt
@@ -0,0 +1,117 @@
+// Signature format: 4.0
+package androidx.benchmark {
+
+ public final class BenchmarkState {
+ ctor @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkStateApi public BenchmarkState(optional Integer? warmupCount, optional Integer? repeatCount);
+ method @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkStateApi public java.util.List<java.lang.Double> getMeasurementTimeNs();
+ method public boolean keepRunning();
+ method public void pauseTiming();
+ method @SuppressCompatibility @androidx.benchmark.BenchmarkState.Companion.ExperimentalExternalReport public static void reportData(String className, String testName, @IntRange(from=0L) long totalRunTimeNs, java.util.List<java.lang.Long> dataNs, @IntRange(from=0L) int warmupIterations, @IntRange(from=0L) long thermalThrottleSleepSeconds, @IntRange(from=1L) int repeatIterations);
+ method public void resumeTiming();
+ field public static final androidx.benchmark.BenchmarkState.Companion Companion;
+ }
+
+ public static final class BenchmarkState.Companion {
+ method @SuppressCompatibility @androidx.benchmark.BenchmarkState.Companion.ExperimentalExternalReport public void reportData(String className, String testName, @IntRange(from=0L) long totalRunTimeNs, java.util.List<java.lang.Long> dataNs, @IntRange(from=0L) int warmupIterations, @IntRange(from=0L) long thermalThrottleSleepSeconds, @IntRange(from=1L) int repeatIterations);
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public static @interface BenchmarkState.Companion.ExperimentalExternalReport {
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalBenchmarkConfigApi {
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalBenchmarkStateApi {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public abstract class MetricCapture {
+ ctor public MetricCapture(java.util.List<java.lang.String> names);
+ method public abstract void capturePaused();
+ method public abstract void captureResumed();
+ method public abstract void captureStart(long timeNs);
+ method public abstract void captureStop(long timeNs, long[] output, int offset);
+ method public final java.util.List<java.lang.String> getNames();
+ property public final java.util.List<java.lang.String> names;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class MicrobenchmarkConfig {
+ ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean shouldEnableTraceAppTag, optional boolean shouldEnablePerfettoSdkTracing, optional androidx.benchmark.ProfilerConfig? profiler);
+ method public java.util.List<androidx.benchmark.MetricCapture> getMetrics();
+ method public androidx.benchmark.ProfilerConfig? getProfiler();
+ method public boolean getShouldEnablePerfettoSdkTracing();
+ method public boolean getShouldEnableTraceAppTag();
+ property public final java.util.List<androidx.benchmark.MetricCapture> metrics;
+ property public final androidx.benchmark.ProfilerConfig? profiler;
+ property public final boolean shouldEnablePerfettoSdkTracing;
+ property public final boolean shouldEnableTraceAppTag;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public abstract sealed class ProfilerConfig {
+ }
+
+ public static final class ProfilerConfig.MethodTracing extends androidx.benchmark.ProfilerConfig {
+ ctor public ProfilerConfig.MethodTracing();
+ }
+
+ public static final class ProfilerConfig.StackSampling extends androidx.benchmark.ProfilerConfig {
+ ctor public ProfilerConfig.StackSampling();
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class TimeCapture extends androidx.benchmark.MetricCapture {
+ ctor public TimeCapture();
+ method public void capturePaused();
+ method public void captureResumed();
+ method public void captureStart(long timeNs);
+ method public void captureStop(long timeNs, long[] output, int offset);
+ }
+
+}
+
+package androidx.benchmark.perfetto {
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalPerfettoCaptureApi {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public abstract sealed class PerfettoConfig {
+ }
+
+ public static final class PerfettoConfig.Binary extends androidx.benchmark.perfetto.PerfettoConfig {
+ ctor public PerfettoConfig.Binary(byte[] bytes);
+ method public byte[] getBytes();
+ property public final byte[] bytes;
+ }
+
+ public static final class PerfettoConfig.Text extends androidx.benchmark.perfetto.PerfettoConfig {
+ ctor public PerfettoConfig.Text(String text);
+ method public String getText();
+ property public final String text;
+ }
+
+ @SuppressCompatibility @RequiresApi(23) @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public final class PerfettoTrace {
+ ctor public PerfettoTrace(String path);
+ method public String getPath();
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ property public final String path;
+ field public static final androidx.benchmark.perfetto.PerfettoTrace.Companion Companion;
+ }
+
+ public static final class PerfettoTrace.Companion {
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ }
+
+}
+
diff --git a/benchmark/benchmark-common/api/res-1.2.0-beta03.txt b/benchmark/benchmark-common/api/res-1.2.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/benchmark/benchmark-common/api/res-1.2.0-beta03.txt
diff --git a/benchmark/benchmark-common/api/restricted_1.2.0-beta03.txt b/benchmark/benchmark-common/api/restricted_1.2.0-beta03.txt
new file mode 100644
index 0000000..fb75b90
--- /dev/null
+++ b/benchmark/benchmark-common/api/restricted_1.2.0-beta03.txt
@@ -0,0 +1,119 @@
+// Signature format: 4.0
+package androidx.benchmark {
+
+ public final class BenchmarkState {
+ ctor @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkStateApi public BenchmarkState(optional Integer? warmupCount, optional Integer? repeatCount);
+ method @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkStateApi public java.util.List<java.lang.Double> getMeasurementTimeNs();
+ method public boolean keepRunning();
+ method @kotlin.PublishedApi internal boolean keepRunningInternal();
+ method public void pauseTiming();
+ method @SuppressCompatibility @androidx.benchmark.BenchmarkState.Companion.ExperimentalExternalReport public static void reportData(String className, String testName, @IntRange(from=0L) long totalRunTimeNs, java.util.List<java.lang.Long> dataNs, @IntRange(from=0L) int warmupIterations, @IntRange(from=0L) long thermalThrottleSleepSeconds, @IntRange(from=1L) int repeatIterations);
+ method public void resumeTiming();
+ field public static final androidx.benchmark.BenchmarkState.Companion Companion;
+ field @kotlin.PublishedApi internal int iterationsRemaining;
+ }
+
+ public static final class BenchmarkState.Companion {
+ method @SuppressCompatibility @androidx.benchmark.BenchmarkState.Companion.ExperimentalExternalReport public void reportData(String className, String testName, @IntRange(from=0L) long totalRunTimeNs, java.util.List<java.lang.Long> dataNs, @IntRange(from=0L) int warmupIterations, @IntRange(from=0L) long thermalThrottleSleepSeconds, @IntRange(from=1L) int repeatIterations);
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public static @interface BenchmarkState.Companion.ExperimentalExternalReport {
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalBenchmarkConfigApi {
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalBenchmarkStateApi {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public abstract class MetricCapture {
+ ctor public MetricCapture(java.util.List<java.lang.String> names);
+ method public abstract void capturePaused();
+ method public abstract void captureResumed();
+ method public abstract void captureStart(long timeNs);
+ method public abstract void captureStop(long timeNs, long[] output, int offset);
+ method public final java.util.List<java.lang.String> getNames();
+ property public final java.util.List<java.lang.String> names;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class MicrobenchmarkConfig {
+ ctor public MicrobenchmarkConfig(optional java.util.List<? extends androidx.benchmark.MetricCapture> metrics, optional boolean shouldEnableTraceAppTag, optional boolean shouldEnablePerfettoSdkTracing, optional androidx.benchmark.ProfilerConfig? profiler);
+ method public java.util.List<androidx.benchmark.MetricCapture> getMetrics();
+ method public androidx.benchmark.ProfilerConfig? getProfiler();
+ method public boolean getShouldEnablePerfettoSdkTracing();
+ method public boolean getShouldEnableTraceAppTag();
+ property public final java.util.List<androidx.benchmark.MetricCapture> metrics;
+ property public final androidx.benchmark.ProfilerConfig? profiler;
+ property public final boolean shouldEnablePerfettoSdkTracing;
+ property public final boolean shouldEnableTraceAppTag;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public abstract sealed class ProfilerConfig {
+ }
+
+ public static final class ProfilerConfig.MethodTracing extends androidx.benchmark.ProfilerConfig {
+ ctor public ProfilerConfig.MethodTracing();
+ }
+
+ public static final class ProfilerConfig.StackSampling extends androidx.benchmark.ProfilerConfig {
+ ctor public ProfilerConfig.StackSampling();
+ }
+
+ @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public final class TimeCapture extends androidx.benchmark.MetricCapture {
+ ctor public TimeCapture();
+ method public void capturePaused();
+ method public void captureResumed();
+ method public void captureStart(long timeNs);
+ method public void captureStop(long timeNs, long[] output, int offset);
+ }
+
+}
+
+package androidx.benchmark.perfetto {
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalPerfettoCaptureApi {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public abstract sealed class PerfettoConfig {
+ }
+
+ public static final class PerfettoConfig.Binary extends androidx.benchmark.perfetto.PerfettoConfig {
+ ctor public PerfettoConfig.Binary(byte[] bytes);
+ method public byte[] getBytes();
+ property public final byte[] bytes;
+ }
+
+ public static final class PerfettoConfig.Text extends androidx.benchmark.perfetto.PerfettoConfig {
+ ctor public PerfettoConfig.Text(String text);
+ method public String getText();
+ property public final String text;
+ }
+
+ @SuppressCompatibility @RequiresApi(23) @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public final class PerfettoTrace {
+ ctor public PerfettoTrace(String path);
+ method public String getPath();
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public static void record(String fileLabel, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ property public final String path;
+ field public static final androidx.benchmark.perfetto.PerfettoTrace.Companion Companion;
+ }
+
+ public static final class PerfettoTrace.Companion {
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, optional String highlightPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, androidx.benchmark.perfetto.PerfettoConfig config, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, optional String? userspaceTracingPackage, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, optional java.util.List<java.lang.String> appTagPackages, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ method public void record(String fileLabel, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+ }
+
+}
+
diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InMemoryTracingTest.kt
similarity index 84%
rename from benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
rename to benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InMemoryTracingTest.kt
index 20f264f..ad72a77 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/UserspaceTracingTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/InMemoryTracingTest.kt
@@ -16,6 +16,7 @@
package androidx.benchmark
+import android.os.Process
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
@@ -23,35 +24,29 @@
import kotlin.test.assertNotNull
import org.junit.After
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import perfetto.protos.ThreadDescriptor
import perfetto.protos.TracePacket
import perfetto.protos.TrackDescriptor
import perfetto.protos.TrackEvent
@RunWith(AndroidJUnit4::class)
@SmallTest
-class UserspaceTracingTest {
+class InMemoryTracingTest {
@Before
@After
fun setup() {
- UserspaceTracing.commitToTrace() // reset
+ InMemoryTracing.clearEvents() // reset
}
@Test
fun emptyTrace() {
- val beforeTime = System.nanoTime()
- UserspaceTracing.commitToTrace() // reset, and trigger first event in next trace
- val afterTime = System.nanoTime()
-
- val trace = UserspaceTracing.commitToTrace() // capture trace
+ val trace = InMemoryTracing.commitToTrace("testLabel") // capture trace
assertEquals(1, trace.packet.size)
val packet = trace.packet.first()
-
- assertTrue(packet.timestamp in beforeTime..afterTime)
assertEquals(
packet,
TracePacket(
@@ -60,7 +55,9 @@
incremental_state_cleared = true,
track_descriptor = TrackDescriptor(
uuid = packet.track_descriptor?.uuid,
- name = "Macrobenchmark"
+ name = "testLabel",
+ thread = ThreadDescriptor(pid = Process.myPid(), tid = Process.myTid()),
+ disallow_merging_with_system_tracks = true
)
)
)
@@ -69,16 +66,19 @@
@Test
fun minimalTrace() {
val beforeTime = System.nanoTime()
- userspaceTrace("test trace section") {}
+ inMemoryTrace("test trace section") {}
val afterTime = System.nanoTime()
- val trace = UserspaceTracing.commitToTrace()
+ val trace = InMemoryTracing.commitToTrace("testLabel")
assertEquals(3, trace.packet.size)
+ // verify track
val descriptor = trace.packet.first().track_descriptor
- assertNotNull(descriptor) // verify track
+ assertNotNull(descriptor)
+ assertEquals("testLabel", descriptor.name)
+ // verify events
trace.packet[1].apply {
assert(timestamp in beforeTime..afterTime)
assertEquals(
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
index f82a89b..0577141 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
@@ -39,19 +39,18 @@
/**
* Set to true to enable androidx.tracing.perfetto tracepoints (such as composition tracing)
*
- * Note this only affects Macrobenchmarks currently, and only when StartupMode.COLD is not used,
- * since enabling the tracepoints wakes the target process
- *
- * Currently internal/experimental
+ * Note that when StartupMode.COLD is used, additional work must be performed during target app
+ * startup to initialize tracing.
*/
- private val _fullTracingEnable: Boolean
- val fullTracingEnable: Boolean get() = fullTracingEnableOverride ?: _fullTracingEnable
+ private val _perfettoSdkTracingEnable: Boolean
+ val perfettoSdkTracingEnable: Boolean get() =
+ perfettoSdkTracingEnableOverride ?: _perfettoSdkTracingEnable
/**
* Allows tests to override whether full tracing is enabled
*/
@VisibleForTesting
- var fullTracingEnableOverride: Boolean? = null
+ var perfettoSdkTracingEnableOverride: Boolean? = null
val enabledRules: Set<RuleType>
@@ -120,8 +119,11 @@
iterations =
arguments.getBenchmarkArgument("iterations")?.toInt()
- _fullTracingEnable =
- (arguments.getBenchmarkArgument("fullTracing.enable")?.toBoolean() ?: false)
+ _perfettoSdkTracingEnable =
+ arguments.getBenchmarkArgument("perfettoSdkTracing.enable")?.toBoolean()
+ // fullTracing.enable is the legacy/compat name
+ ?: arguments.getBenchmarkArgument("fullTracing.enable")?.toBoolean()
+ ?: false
// Transform comma-delimited list into set of suppressed errors
// E.g. "DEBUGGABLE, UNLOCKED" -> setOf("DEBUGGABLE", "UNLOCKED")
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
index b6ab1fc..6df6bcd 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/BenchmarkState.kt
@@ -250,7 +250,7 @@
if (phaseIndex >= 0) {
currentPhase.profiler?.stop()
- UserspaceTracing.endSection()
+ InMemoryTracing.endSection()
thermalThrottleSleepSeconds += currentPhase.thermalThrottleSleepSeconds
if (currentPhase.loopMode.warmupManager == null && currentPhase.profiler == null) {
// Always save metrics, except during warmup / profiling
@@ -282,7 +282,7 @@
iterationsPerRepeat = iterationsPerRepeat.coerceAtLeast(currentLoopsPerMeasurement)
- UserspaceTracing.beginSection(currentPhase.label)
+ InMemoryTracing.beginSection(currentPhase.label)
val phaseProfilerResult = currentPhase.profiler?.start(traceUniqueName)
if (phaseProfilerResult != null) {
require(profilerResult == null) {
@@ -385,7 +385,7 @@
if (!value) {
ThreadPriority.resetBumpedThread()
if (phaseIndex >= 0 && phaseIndex <= phases.size) {
- UserspaceTracing.endSection() // current phase cancelled, complete trace event
+ InMemoryTracing.endSection() // current phase cancelled, complete trace event
}
throw IllegalStateException(lazyMessage())
}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
index a8169f6..b76a27e 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/DeviceInfo.kt
@@ -40,6 +40,9 @@
val typeLabel = if (isEmulator) "emulator" else "device"
val isEngBuild = Build.FINGERPRINT.contains(":eng/")
+ private val isUserdebugBuild = Build.FINGERPRINT.contains(":userdebug/")
+
+ val profileableEnforced = !isEngBuild && !isUserdebugBuild
val isRooted = Build.FINGERPRINT.contains(":userdebug/") ||
arrayOf(
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Errors.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Errors.kt
index 20510f6..301f45e 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Errors.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Errors.kt
@@ -189,7 +189,9 @@
| be avoided, due to measurement inaccuracy.
""".trimMarginWrapNewlines()
} else if (
- Build.VERSION.SDK_INT >= 29 && !context.isProfileableByShell()
+ DeviceInfo.profileableEnforced &&
+ Build.VERSION.SDK_INT >= 29 &&
+ !context.isProfileableByShell()
) {
warningPrefix += "SIMPLEPERF_"
warningString += """
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/InMemoryTracing.kt
similarity index 67%
rename from benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
rename to benchmark/benchmark-common/src/main/java/androidx/benchmark/InMemoryTracing.kt
index 5972a77..4b171eb 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/UserspaceTracing.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/InMemoryTracing.kt
@@ -16,25 +16,32 @@
package androidx.benchmark
+import android.os.Process
import androidx.annotation.RestrictTo
+import androidx.benchmark.InMemoryTracing.commitToTrace
+import perfetto.protos.ThreadDescriptor
import perfetto.protos.Trace
import perfetto.protos.TracePacket
import perfetto.protos.TrackDescriptor
import perfetto.protos.TrackEvent
/**
- * Userspace-buffer-based tracing api, that provides implementation for [userspaceTrace].
+ * Tracing api that writes events directly into memory.
*
- * This records while atrace isn't capturing by storing trace events manually in a list of
- * in-userspace-memory perfetto protos.
+ * This has a few advantages over typical atrace:
+ * - can record while atrace isn't captured either due to platform limitations (old platforms may
+ * only allow one process to be traced at a time), or when debugging benchmark performance, it can
+ * capture when atrace isn't active (e.g. tracing the start/stop of perfetto)
+ * - can create events asynchronously, deferring record cost (e.g. micro creating events after all
+ * measurements, using existing timestamps)
+ * - can customize presentation of events in trace
*
* After trace processing, the extra events (before _and_ after the measureBlock section of a
* benchmark) can be added to the trace by calling [commitToTrace], and appending that to the
* trace on-disk.
- *
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-object UserspaceTracing {
+object InMemoryTracing {
/**
* All events emitted by the benchmark annotation should have the same value.
* the value needs to not conflict with any sequence id emitted in the trace.
@@ -58,39 +65,44 @@
private const val CLOCK_ID = 3
/**
- * Name of track in for userspace tracing events
- */
- private const val TRACK_DESCRIPTOR_NAME = "Macrobenchmark"
-
- /**
* Tag to enable post-filtering of events in the trace.
*/
private val TRACK_EVENT_CATEGORIES = listOf("benchmark")
- private fun createInitialTracePacket() = TracePacket(
- timestamp = System.nanoTime(),
- timestamp_clock_id = CLOCK_ID,
- incremental_state_cleared = true,
- track_descriptor = TrackDescriptor(
- uuid = UUID,
- name = TRACK_DESCRIPTOR_NAME
- )
- )
-
/**
* For perf/simplicity, this isn't protected by a lock - it should only every be
* accessed by the test thread, and dumped/reset between tests.
*/
- val events = mutableListOf(createInitialTracePacket())
+ val events = mutableListOf<TracePacket>()
+
+ fun clearEvents() {
+ events.clear()
+ }
/**
* Capture trace state, and return as a Trace(), which can be appended to a trace file.
*/
- fun commitToTrace(): Trace {
+ fun commitToTrace(
+ label: String
+ ): Trace {
val capturedEvents = events.toList()
- events.clear()
- events.add(createInitialTracePacket())
- return Trace(capturedEvents)
+ clearEvents()
+ return Trace(
+ listOf(
+ TracePacket(
+ timestamp_clock_id = CLOCK_ID,
+ incremental_state_cleared = true,
+ track_descriptor = TrackDescriptor(
+ uuid = UUID,
+ name = label,
+ thread = ThreadDescriptor(pid = Process.myPid(), tid = Process.myTid()),
+ // currently separate for clarity, to allow InMemoryTrace events to have a visible
+ // track name, but not override the thread name
+ disallow_merging_with_system_tracks = true
+ )
+ )
+ ) + capturedEvents
+ )
}
fun beginSection(label: String, nanoTime: Long = System.nanoTime()) {
@@ -125,11 +137,11 @@
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-inline fun <T> userspaceTrace(label: String, block: () -> T): T {
- UserspaceTracing.beginSection(label)
+inline fun <T> inMemoryTrace(label: String, block: () -> T): T {
+ InMemoryTracing.beginSection(label)
return try {
block()
} finally {
- UserspaceTracing.endSection()
+ InMemoryTracing.endSection()
}
}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
index 50e30ad..d0ae847 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MetricsContainer.kt
@@ -54,7 +54,7 @@
internal val data: List<LongArray> = List(repeatCount) { LongArray(names.size) }
/**
- * Array of start / stop time, per measurement, to be passed to [UserspaceTracing].
+ * Array of start / stop time, per measurement, to be passed to [InMemoryTracing].
*
* These values are used both in metric calculation and trace data, so tracing is extremely low
* overhead - just the cost of storing the timing data in an additional place in memory.
@@ -135,8 +135,8 @@
*/
fun captureFinished(maxIterations: Int): List<MetricResult> {
for (i in 0..repeatTiming.lastIndex step 2) {
- UserspaceTracing.beginSection("measurement ${i / 2}", nanoTime = repeatTiming[i])
- UserspaceTracing.endSection(nanoTime = repeatTiming[i + 1])
+ InMemoryTracing.beginSection("measurement ${i / 2}", nanoTime = repeatTiming[i])
+ InMemoryTracing.endSection(nanoTime = repeatTiming[i + 1])
}
return names.mapIndexed { index, name ->
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt
index e8cba451..a21e9c8 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/MicrobenchmarkPhase.kt
@@ -53,7 +53,7 @@
"THERMAL THROTTLE DETECTED, SLEEPING FOR $THROTTLE_BACKOFF_S SECONDS"
)
val startTimeNs = System.nanoTime()
- userspaceTrace("Sleep due to Thermal Throttle") {
+ inMemoryTrace("Sleep due to Thermal Throttle") {
Thread.sleep(TimeUnit.SECONDS.toMillis(THROTTLE_BACKOFF_S))
}
val sleepTimeNs = System.nanoTime() - startTimeNs
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/RunListenerDelegate.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/RunListenerDelegate.kt
new file mode 100644
index 0000000..b9332af
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/RunListenerDelegate.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import android.util.Log
+import androidx.annotation.RestrictTo
+
+/**
+ * Actions that need to be performed once per test suite are defined in this [RunListenerDelegate].
+ *
+ * This way, we minimize the costs of these suite wide actions, and benchmarks continue running
+ * fast (with minimal additional overheads).
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class RunListenerDelegate(private val sideEffects: List<SideEffect>) {
+ /**
+ * Called before any tests have been run.
+ */
+ fun onTestRunStarted() {
+ sideEffects.forEach { sideEffect ->
+ Log.d(
+ BenchmarkState.TAG,
+ "Setting up side effect ${sideEffect.name()}"
+ )
+ sideEffect.setup()
+ }
+ }
+
+ /**
+ * Called after all tests have been completed.
+ */
+ fun onTestRunFinished() {
+ sideEffects.forEach { sideEffect ->
+ Log.d(
+ BenchmarkState.TAG,
+ "Tearing down side effect ${sideEffect.name()}"
+ )
+ sideEffect.tearDown()
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
index faabcf9..6811685 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
@@ -588,7 +588,7 @@
if (runningProcesses.isEmpty()) {
return
}
- userspaceTrace("wait for $runningProcesses to die") {
+ inMemoryTrace("wait for $runningProcesses to die") {
SystemClock.sleep(waitPollPeriodMs)
}
Log.d(BenchmarkState.TAG, "Waiting $waitPollPeriodMs ms for $runningProcesses to die")
@@ -611,6 +611,34 @@
}
@RequiresApi(21)
+ fun disablePackages(appPackages: List<String>) {
+ val command = appPackages.joinToString(separator = "\n") { appPackage ->
+ "pm disable-user $appPackage"
+ }
+ executeScriptCaptureStdoutStderr(command)
+ }
+
+ @RequiresApi(21)
+ fun enablePackages(appPackages: List<String>) {
+ val command = appPackages.joinToString(separator = "\n") { appPackage ->
+ "pm enable $appPackage"
+ }
+ executeScriptCaptureStdoutStderr(command)
+ }
+
+ @RequiresApi(24)
+ fun disableBackgroundDexOpt() {
+ // Cancels the active job if any
+ ShellImpl.executeCommandUnsafe("cmd package bg-dexopt-job --cancel")
+ ShellImpl.executeCommandUnsafe("cmd package bg-dexopt-job --disable")
+ }
+
+ @RequiresApi(24)
+ fun enableBackgroundDexOpt() {
+ ShellImpl.executeCommandUnsafe("cmd package bg-dexopt-job --enable")
+ }
+
+ @RequiresApi(21)
fun isSELinuxEnforced(): Boolean {
return when (val value = executeScriptCaptureStdout("getenforce").trim()) {
"Permissive" -> false
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffect.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffect.kt
new file mode 100644
index 0000000..512851d
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffect.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import androidx.annotation.RestrictTo
+
+/**
+* Represents actions that effect changes to the state of the app / device outside of the scope
+* of the benchmark. Typically used to help reduce the amount of interference during a benchmark.
+*
+* [SideEffect]s must define a [setup], that is executed when the benchmark starts. The [tearDown]
+* method is called during the end of the benchmark to reverse actions so subsequent invocations of
+* the benchmark are hermetic.
+*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+interface SideEffect {
+
+ /**
+ * Returns the canonical name of the [SideEffect].
+ */
+ fun name(): String
+
+ /**
+ * This method is executed when the benchmark starts.
+ */
+ fun setup()
+
+ /**
+ * This method is executed when the benchmark is complete. A [SideEffect] should undo
+ * the changes to the state of the device app, to ensure hermetic benchmarks.
+ */
+ fun tearDown()
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffects.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffects.kt
new file mode 100644
index 0000000..c520311
--- /dev/null
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/SideEffects.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark
+
+import android.os.Build
+import android.util.Log
+import androidx.annotation.RestrictTo
+
+/**
+ * Disables the [packages] during the course of a benchmark thereby reducing the amount of noise.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class DisablePackages(
+ private val packages: List<String> = DEFAULT_PACKAGES_TO_DISABLE
+) : SideEffect {
+ override fun name(): String {
+ return "DisablePackages"
+ }
+
+ override fun setup() {
+ if (Build.VERSION.SDK_INT >= 21) {
+ Log.d(BenchmarkState.TAG, "Disabling packages $packages")
+ Shell.disablePackages(packages)
+ }
+ }
+
+ override fun tearDown() {
+ if (Build.VERSION.SDK_INT >= 21) {
+ Log.d(BenchmarkState.TAG, "Re-enabling packages $packages")
+ Shell.enablePackages(packages)
+ }
+ }
+
+ companion object {
+ // A list of packages to disable + "com.google.android.gms"
+ // https://source.corp.google.com/piper///depot/google3/java/com/google/android/libraries/swpower/fixture/DisableModule.java
+ internal val DEFAULT_PACKAGES_TO_DISABLE = listOf(
+ "com.android.chrome",
+ "com.android.phone",
+ "com.android.ramdump",
+ "com.android.vending",
+ "com.google.android.apps.docs",
+ "com.google.android.apps.gcs",
+ "com.google.android.apps.internal.betterbug",
+ "com.google.android.apps.maps",
+ "com.google.android.apps.messaging",
+ "com.google.android.apps.nbu.files",
+ "com.google.android.apps.photos",
+ "com.google.android.apps.scone",
+ "com.google.android.apps.tips",
+ "com.google.android.apps.turbo",
+ "com.google.android.apps.tycho",
+ "com.google.android.apps.work.clouddpc",
+ "com.google.android.apps.youtube.music",
+ "com.google.android.as",
+ "com.google.android.calculator",
+ "com.google.android.calendar",
+ "com.google.android.configupdater",
+ "com.google.android.contacts",
+ "com.google.android.deskclock",
+ "com.google.android.dialer",
+ "com.google.android.googlequicksearchbox",
+ "com.google.android.gm",
+ "com.google.android.gms",
+ "com.google.android.GoogleCamera",
+ "com.google.android.ims",
+ "com.google.android.inputmethod.latin",
+ "com.google.android.marvin.talkback",
+ "com.google.android.partnersetup",
+ "com.google.android.settings.intelligence",
+ "com.google.android.tts",
+ "com.google.android.videos",
+ "com.google.android.youtube",
+ "com.google.android.videos",
+ "com.google.android.volta"
+ )
+ }
+}
+
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class DisableDexOpt : SideEffect {
+ override fun name(): String {
+ return "DisableDexOpt"
+ }
+
+ override fun setup() {
+ // PGO was enabled on Android N
+ if (Build.VERSION.SDK_INT >= 24) {
+ Shell.disableBackgroundDexOpt()
+ }
+ }
+
+ override fun tearDown() {
+ if (Build.VERSION.SDK_INT >= 24) {
+ Shell.enableBackgroundDexOpt()
+ }
+ }
+}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
index 8cd40a0..2f5a387 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
@@ -22,9 +22,9 @@
import androidx.annotation.RestrictTo
import androidx.benchmark.Outputs
import androidx.benchmark.Shell
+import androidx.benchmark.inMemoryTrace
import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig.InitialProcessState
import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
-import androidx.benchmark.userspaceTrace
import androidx.test.platform.app.InstrumentationRegistry
import androidx.tracing.perfetto.handshake.PerfettoSdkHandshake
import androidx.tracing.perfetto.handshake.protocol.ResponseResultCodes.RESULT_CODE_ALREADY_ENABLED
@@ -57,18 +57,18 @@
/**
* Start collecting perfetto trace.
*/
- fun start(config: PerfettoConfig) = userspaceTrace("start perfetto") {
+ fun start(config: PerfettoConfig) = inMemoryTrace("start perfetto") {
// Write config proto to dir that shell can read
// We use `.pb` even with textproto so we'll only ever have one file
val configProtoFile = File(Outputs.dirUsableByAppAndShell, "trace_config.pb")
try {
- userspaceTrace("write config") {
+ inMemoryTrace("write config") {
config.writeTo(configProtoFile)
if (Outputs.forceFilesForShellAccessible) {
configProtoFile.setReadable(true, /* ownerOnly = */ false)
}
}
- userspaceTrace("start perfetto process") {
+ inMemoryTrace("start perfetto process") {
helper.startCollecting(configProtoFile.absolutePath, config.isTextProto)
}
} finally {
@@ -82,7 +82,7 @@
* @param destinationPath Absolute path to write perfetto trace to. Must be shell-writable,
* such as result of `context.getExternalFilesDir(null)` or other similar `external` paths.
*/
- public fun stop(destinationPath: String) = userspaceTrace("stop perfetto") {
+ public fun stop(destinationPath: String) = inMemoryTrace("stop perfetto") {
helper.stopCollecting(destinationPath)
}
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
index 278416e..c823e02 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoCaptureWrapper.kt
@@ -20,12 +20,14 @@
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
+import androidx.benchmark.InMemoryTracing
import androidx.benchmark.Outputs
import androidx.benchmark.Outputs.dateToFileName
import androidx.benchmark.PropOverride
import androidx.benchmark.Shell
import androidx.benchmark.perfetto.PerfettoHelper.Companion.LOG_TAG
import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
+import java.io.File
/**
* Wrapper for [PerfettoCapture] which does nothing below API 23.
@@ -93,6 +95,7 @@
perfettoSdkConfig: PerfettoCapture.PerfettoSdkConfig?,
traceCallback: ((String) -> Unit)? = null,
enableTracing: Boolean = true,
+ inMemoryTracingLabel: String? = null,
block: () -> Unit
): String? {
// skip if Perfetto not supported, or if caller opts out
@@ -122,11 +125,20 @@
try {
propOverride?.forceValue()
start(config, perfettoSdkConfig)
+
+ // To avoid b/174007010, userspace tracing is cleared and saved *during* trace, so
+ // that events won't lie outside the bounds of the trace content.
+ InMemoryTracing.clearEvents()
try {
block()
} finally {
// finally here to ensure trace is fully recorded if block throws
path = stop(fileLabel)
+
+ if (inMemoryTracingLabel != null) {
+ val inMemoryTrace = InMemoryTracing.commitToTrace(inMemoryTracingLabel)
+ File(path).appendBytes(inMemoryTrace.encode())
+ }
traceCallback?.invoke(path)
}
return path
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
index 2491c74..b4fdbc1 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
@@ -23,8 +23,8 @@
import androidx.annotation.RestrictTo
import androidx.benchmark.DeviceInfo.deviceSummaryString
import androidx.benchmark.Shell
+import androidx.benchmark.inMemoryTrace
import androidx.benchmark.perfetto.PerfettoHelper.Companion.MIN_SDK_VERSION
-import androidx.benchmark.userspaceTrace
import androidx.test.platform.app.InstrumentationRegistry
import androidx.tracing.trace
import java.io.File
@@ -165,7 +165,7 @@
* This is a good indicator that tracing is actually enabled (including the app atrace tag), and
* that content will be captured in the trace buffer
*/
- private fun checkTracingOn(): Unit = userspaceTrace("poll tracing_on") {
+ private fun checkTracingOn(): Unit = inMemoryTrace("poll tracing_on") {
val path: String = when {
Shell.pathExists(TRACING_ON_PATH) -> {
TRACING_ON_PATH
@@ -187,7 +187,7 @@
repeat(pollTracingOnMaxCount) {
when (val output = Shell.executeScriptCaptureStdout("cat $path").trim()) {
"0" -> {
- userspaceTrace("wait for trace to start (tracing_on == 1)") {
+ inMemoryTrace("wait for trace to start (tracing_on == 1)") {
SystemClock.sleep(pollTracingOnMs)
}
}
@@ -232,12 +232,12 @@
// Stop the perfetto and copy the output file.
Log.i(LOG_TAG, "Stopping perfetto.")
- userspaceTrace("stop perfetto process") {
+ inMemoryTrace("stop perfetto process") {
stopPerfetto()
}
Log.i(LOG_TAG, "Writing to $destinationFile.")
- userspaceTrace("copy trace to output dir") {
+ inMemoryTrace("copy trace to output dir") {
copyFileOutput(destinationFile)
}
}
@@ -410,7 +410,7 @@
}
fun createExecutable(tool: String): String {
- userspaceTrace("create executable: $tool") {
+ inMemoryTrace("create executable: $tool") {
if (!isAbiSupported()) {
throw IllegalStateException(
"Unsupported ABI (${Build.SUPPORTED_ABIS.joinToString()})"
diff --git a/benchmark/benchmark-junit4/api/1.2.0-beta03.txt b/benchmark/benchmark-junit4/api/1.2.0-beta03.txt
new file mode 100644
index 0000000..aea3355
--- /dev/null
+++ b/benchmark/benchmark-junit4/api/1.2.0-beta03.txt
@@ -0,0 +1,35 @@
+// Signature format: 4.0
+package androidx.benchmark.junit4 {
+
+ public class AndroidBenchmarkRunner extends androidx.test.runner.AndroidJUnitRunner {
+ ctor public AndroidBenchmarkRunner();
+ }
+
+ public final class BenchmarkRule implements org.junit.rules.TestRule {
+ ctor public BenchmarkRule();
+ ctor @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public BenchmarkRule(androidx.benchmark.MicrobenchmarkConfig config);
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public androidx.benchmark.BenchmarkState getState();
+ }
+
+ public final class BenchmarkRule.Scope {
+ method public inline <T> T runWithTimingDisabled(kotlin.jvm.functions.Function0<? extends T> block);
+ }
+
+ public final class BenchmarkRuleKt {
+ method public static inline void measureRepeated(androidx.benchmark.junit4.BenchmarkRule, kotlin.jvm.functions.Function1<? super androidx.benchmark.junit4.BenchmarkRule.Scope,kotlin.Unit> block);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public final class PerfettoTraceRule implements org.junit.rules.TestRule {
+ ctor public PerfettoTraceRule(optional boolean enableAppTagTracing, optional boolean enableUserspaceTracing, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback);
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public boolean getEnableAppTagTracing();
+ method public boolean getEnableUserspaceTracing();
+ method public kotlin.jvm.functions.Function1<androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? getTraceCallback();
+ property public final boolean enableAppTagTracing;
+ property public final boolean enableUserspaceTracing;
+ property public final kotlin.jvm.functions.Function1<androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback;
+ }
+
+}
+
diff --git a/benchmark/benchmark-junit4/api/res-1.2.0-beta03.txt b/benchmark/benchmark-junit4/api/res-1.2.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/benchmark/benchmark-junit4/api/res-1.2.0-beta03.txt
diff --git a/benchmark/benchmark-junit4/api/restricted_1.2.0-beta03.txt b/benchmark/benchmark-junit4/api/restricted_1.2.0-beta03.txt
new file mode 100644
index 0000000..0dab2ea
--- /dev/null
+++ b/benchmark/benchmark-junit4/api/restricted_1.2.0-beta03.txt
@@ -0,0 +1,36 @@
+// Signature format: 4.0
+package androidx.benchmark.junit4 {
+
+ public class AndroidBenchmarkRunner extends androidx.test.runner.AndroidJUnitRunner {
+ ctor public AndroidBenchmarkRunner();
+ }
+
+ public final class BenchmarkRule implements org.junit.rules.TestRule {
+ ctor public BenchmarkRule();
+ ctor @SuppressCompatibility @androidx.benchmark.ExperimentalBenchmarkConfigApi public BenchmarkRule(androidx.benchmark.MicrobenchmarkConfig config);
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public androidx.benchmark.BenchmarkState getState();
+ }
+
+ public final class BenchmarkRule.Scope {
+ method @kotlin.PublishedApi internal androidx.benchmark.BenchmarkState getOuterState();
+ method public inline <T> T runWithTimingDisabled(kotlin.jvm.functions.Function0<? extends T> block);
+ }
+
+ public final class BenchmarkRuleKt {
+ method public static inline void measureRepeated(androidx.benchmark.junit4.BenchmarkRule, kotlin.jvm.functions.Function1<? super androidx.benchmark.junit4.BenchmarkRule.Scope,kotlin.Unit> block);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoCaptureApi public final class PerfettoTraceRule implements org.junit.rules.TestRule {
+ ctor public PerfettoTraceRule(optional boolean enableAppTagTracing, optional boolean enableUserspaceTracing, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback);
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public boolean getEnableAppTagTracing();
+ method public boolean getEnableUserspaceTracing();
+ method public kotlin.jvm.functions.Function1<androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? getTraceCallback();
+ property public final boolean enableAppTagTracing;
+ property public final boolean enableUserspaceTracing;
+ property public final kotlin.jvm.functions.Function1<androidx.benchmark.perfetto.PerfettoTrace,kotlin.Unit>? traceCallback;
+ }
+
+}
+
diff --git a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
index 5fcf6977..c39aaf8 100644
--- a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
+++ b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/BenchmarkRule.kt
@@ -25,7 +25,6 @@
import androidx.benchmark.DeviceInfo
import androidx.benchmark.ExperimentalBenchmarkConfigApi
import androidx.benchmark.MicrobenchmarkConfig
-import androidx.benchmark.UserspaceTracing
import androidx.benchmark.perfetto.PerfettoCapture
import androidx.benchmark.perfetto.PerfettoCaptureWrapper
import androidx.benchmark.perfetto.PerfettoConfig
@@ -217,8 +216,6 @@
val uniqueName = description.testClass.simpleName + "_" + invokeMethodName
internalState.traceUniqueName = uniqueName
- var userspaceTrace: perfetto.protos.Trace? = null
-
val tracePath = PerfettoCaptureWrapper().record(
fileLabel = uniqueName,
config = PerfettoConfig.Benchmark(
@@ -245,19 +242,13 @@
// Optimize throughput in dryRunMode, since trace isn't useful, and extremely
// expensive on some emulators. Could alternately use UserspaceTracing if desired
// Additionally, skip on misconfigured devices to still enable benchmarking.
- enableTracing = !Arguments.dryRunMode && !DeviceInfo.misconfiguredForTracing
+ enableTracing = !Arguments.dryRunMode && !DeviceInfo.misconfiguredForTracing,
+ inMemoryTracingLabel = "Microbenchmark"
) {
- UserspaceTracing.commitToTrace() // clear buffer
-
trace(description.displayName) { base.evaluate() }
-
- // To avoid b/174007010, userspace tracing is cleared and saved *during* trace, so
- // that events won't lie outside the bounds of the trace content.
- userspaceTrace = UserspaceTracing.commitToTrace()
}?.apply {
// trace completed, and copied into shell writeable dir
val file = File(this)
- file.appendBytes(userspaceTrace!!.encode())
file.appendUiState(
UiState(
timelineStart = null,
diff --git a/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/SideEffectRunListener.kt b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/SideEffectRunListener.kt
new file mode 100644
index 0000000..fa14e63
--- /dev/null
+++ b/benchmark/benchmark-junit4/src/main/java/androidx/benchmark/junit4/SideEffectRunListener.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.junit4
+
+import androidx.annotation.RestrictTo
+import androidx.benchmark.DisableDexOpt
+import androidx.benchmark.DisablePackages
+import androidx.benchmark.RunListenerDelegate
+import org.junit.runner.Description
+import org.junit.runner.Result
+import org.junit.runner.notification.RunListener
+
+/**
+ * Enables the use of side-effects that reduce the noise during a benchmark run.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class SideEffectRunListener : RunListener() {
+ private val delegate: RunListenerDelegate = RunListenerDelegate(
+ sideEffects = listOf(
+ DisablePackages(),
+ DisableDexOpt(),
+ )
+ )
+
+ override fun testRunStarted(description: Description) {
+ super.testRunStarted(description)
+ delegate.onTestRunStarted()
+ }
+
+ override fun testRunFinished(result: Result) {
+ super.testRunFinished(result)
+ delegate.onTestRunFinished()
+ }
+}
diff --git a/benchmark/benchmark-macro-junit4/api/1.2.0-beta03.txt b/benchmark/benchmark-macro-junit4/api/1.2.0-beta03.txt
new file mode 100644
index 0000000..d4c3495
--- /dev/null
+++ b/benchmark/benchmark-macro-junit4/api/1.2.0-beta03.txt
@@ -0,0 +1,26 @@
+// Signature format: 4.0
+package androidx.benchmark.macro.junit4 {
+
+ @RequiresApi(28) public final class BaselineProfileRule implements org.junit.rules.TestRule {
+ ctor public BaselineProfileRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, optional boolean includeInStartupProfile, optional boolean strictStability, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, optional boolean includeInStartupProfile, optional boolean strictStability, optional kotlin.jvm.functions.Function1<? super java.lang.String,java.lang.Boolean> filterPredicate, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, optional boolean includeInStartupProfile, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ }
+
+ public final class MacrobenchmarkRule implements org.junit.rules.TestRule {
+ ctor public MacrobenchmarkRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ }
+
+}
+
diff --git a/benchmark/benchmark-macro-junit4/api/res-1.2.0-beta03.txt b/benchmark/benchmark-macro-junit4/api/res-1.2.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/benchmark/benchmark-macro-junit4/api/res-1.2.0-beta03.txt
diff --git a/benchmark/benchmark-macro-junit4/api/restricted_1.2.0-beta03.txt b/benchmark/benchmark-macro-junit4/api/restricted_1.2.0-beta03.txt
new file mode 100644
index 0000000..d4c3495
--- /dev/null
+++ b/benchmark/benchmark-macro-junit4/api/restricted_1.2.0-beta03.txt
@@ -0,0 +1,26 @@
+// Signature format: 4.0
+package androidx.benchmark.macro.junit4 {
+
+ @RequiresApi(28) public final class BaselineProfileRule implements org.junit.rules.TestRule {
+ ctor public BaselineProfileRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, optional boolean includeInStartupProfile, optional boolean strictStability, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, optional boolean includeInStartupProfile, optional boolean strictStability, optional kotlin.jvm.functions.Function1<? super java.lang.String,java.lang.Boolean> filterPredicate, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, optional boolean includeInStartupProfile, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, optional String? outputFilePrefix, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, optional int stableIterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, optional int maxIterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ method public void collect(String packageName, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> profileBlock);
+ }
+
+ public final class MacrobenchmarkRule implements org.junit.rules.TestRule {
+ ctor public MacrobenchmarkRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, optional androidx.benchmark.macro.StartupMode? startupMode, @IntRange(from=1L) int iterations, optional kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> setupBlock, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, optional androidx.benchmark.macro.CompilationMode compilationMode, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ method public void measureRepeated(String packageName, java.util.List<? extends androidx.benchmark.macro.Metric> metrics, @IntRange(from=1L) int iterations, kotlin.jvm.functions.Function1<? super androidx.benchmark.macro.MacrobenchmarkScope,kotlin.Unit> measureBlock);
+ }
+
+}
+
diff --git a/benchmark/benchmark-macro/api/1.2.0-beta02.txt b/benchmark/benchmark-macro/api/1.2.0-beta02.txt
index 6b770f4..54c8a8c 100644
--- a/benchmark/benchmark-macro/api/1.2.0-beta02.txt
+++ b/benchmark/benchmark-macro/api/1.2.0-beta02.txt
@@ -208,7 +208,7 @@
}
@SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
- ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+ ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
}
public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/api/1.2.0-beta03.txt b/benchmark/benchmark-macro/api/1.2.0-beta03.txt
new file mode 100644
index 0000000..54c8a8c
--- /dev/null
+++ b/benchmark/benchmark-macro/api/1.2.0-beta03.txt
@@ -0,0 +1,261 @@
+// Signature format: 4.0
+package androidx.benchmark.macro {
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class AudioUnderrunMetric extends androidx.benchmark.macro.Metric {
+ ctor public AudioUnderrunMetric();
+ }
+
+ public enum BaselineProfileMode {
+ method public static androidx.benchmark.macro.BaselineProfileMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.BaselineProfileMode[] values();
+ enum_constant public static final androidx.benchmark.macro.BaselineProfileMode Disable;
+ enum_constant public static final androidx.benchmark.macro.BaselineProfileMode Require;
+ enum_constant public static final androidx.benchmark.macro.BaselineProfileMode UseIfAvailable;
+ }
+
+ public abstract sealed class CompilationMode {
+ field public static final androidx.benchmark.macro.CompilationMode.Companion Companion;
+ field public static final androidx.benchmark.macro.CompilationMode DEFAULT;
+ }
+
+ public static final class CompilationMode.Companion {
+ }
+
+ public static final class CompilationMode.Full extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.Full();
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMacrobenchmarkApi public static final class CompilationMode.Ignore extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.Ignore();
+ }
+
+ @RequiresApi(24) public static final class CompilationMode.None extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.None();
+ }
+
+ @RequiresApi(24) public static final class CompilationMode.Partial extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.Partial();
+ ctor public CompilationMode.Partial(optional androidx.benchmark.macro.BaselineProfileMode baselineProfileMode);
+ ctor public CompilationMode.Partial(optional androidx.benchmark.macro.BaselineProfileMode baselineProfileMode, optional @IntRange(from=0L) int warmupIterations);
+ method public androidx.benchmark.macro.BaselineProfileMode getBaselineProfileMode();
+ method public int getWarmupIterations();
+ property public final androidx.benchmark.macro.BaselineProfileMode baselineProfileMode;
+ property public final int warmupIterations;
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This Macrobenchmark API is experimental.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalMacrobenchmarkApi {
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This Metric API is experimental.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalMetricApi {
+ }
+
+ public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
+ ctor public FrameTimingMetric();
+ }
+
+ public final class MacrobenchmarkScope {
+ ctor public MacrobenchmarkScope(String packageName, boolean launchWithClearTask);
+ method public void dropKernelPageCache();
+ method public void dropShaderCache();
+ method public androidx.test.uiautomator.UiDevice getDevice();
+ method public Integer? getIteration();
+ method public String getPackageName();
+ method public void killProcess();
+ method public void killProcess(optional boolean useKillAll);
+ method public void pressHome();
+ method public void pressHome(optional long delayDurationMs);
+ method public void startActivityAndWait();
+ method public void startActivityAndWait(android.content.Intent intent);
+ method public void startActivityAndWait(optional kotlin.jvm.functions.Function1<? super android.content.Intent,kotlin.Unit> block);
+ property public final androidx.test.uiautomator.UiDevice device;
+ property public final Integer? iteration;
+ property public final String packageName;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class MemoryCountersMetric extends androidx.benchmark.macro.TraceMetric {
+ ctor public MemoryCountersMetric();
+ method public java.util.List<androidx.benchmark.macro.Metric.Measurement> getResult(androidx.benchmark.macro.Metric.CaptureInfo captureInfo, androidx.benchmark.perfetto.PerfettoTraceProcessor.Session traceSession);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class MemoryUsageMetric extends androidx.benchmark.macro.TraceMetric {
+ ctor public MemoryUsageMetric(androidx.benchmark.macro.MemoryUsageMetric.Mode mode, optional java.util.List<? extends androidx.benchmark.macro.MemoryUsageMetric.SubMetric> subMetrics);
+ method public java.util.List<androidx.benchmark.macro.Metric.Measurement> getResult(androidx.benchmark.macro.Metric.CaptureInfo captureInfo, androidx.benchmark.perfetto.PerfettoTraceProcessor.Session traceSession);
+ }
+
+ public enum MemoryUsageMetric.Mode {
+ method public static androidx.benchmark.macro.MemoryUsageMetric.Mode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.MemoryUsageMetric.Mode[] values();
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.Mode Last;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.Mode Max;
+ }
+
+ public enum MemoryUsageMetric.SubMetric {
+ method public static androidx.benchmark.macro.MemoryUsageMetric.SubMetric valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.MemoryUsageMetric.SubMetric[] values();
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric Gpu;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric HeapSize;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric RssAnon;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric RssFile;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric RssShmem;
+ }
+
+ public abstract sealed class Metric {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public static final class Metric.CaptureInfo {
+ ctor public Metric.CaptureInfo(int apiLevel, String targetPackageName, String testPackageName, androidx.benchmark.macro.StartupMode? startupMode);
+ method public int component1();
+ method public String component2();
+ method public String component3();
+ method public androidx.benchmark.macro.StartupMode? component4();
+ method public androidx.benchmark.macro.Metric.CaptureInfo copy(int apiLevel, String targetPackageName, String testPackageName, androidx.benchmark.macro.StartupMode? startupMode);
+ method public int getApiLevel();
+ method public androidx.benchmark.macro.StartupMode? getStartupMode();
+ method public String getTargetPackageName();
+ method public String getTestPackageName();
+ property public final int apiLevel;
+ property public final androidx.benchmark.macro.StartupMode? startupMode;
+ property public final String targetPackageName;
+ property public final String testPackageName;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public static final class Metric.Measurement {
+ ctor public Metric.Measurement(String name, double data);
+ ctor public Metric.Measurement(String name, java.util.List<java.lang.Double> dataSamples);
+ method public String component1();
+ method public java.util.List<java.lang.Double> component2();
+ method public boolean component3();
+ method public androidx.benchmark.macro.Metric.Measurement copy(String name, java.util.List<java.lang.Double> data, boolean requireSingleValue);
+ method public java.util.List<java.lang.Double> getData();
+ method public String getName();
+ method public boolean getRequireSingleValue();
+ property public final java.util.List<java.lang.Double> data;
+ property public final String name;
+ property public final boolean requireSingleValue;
+ }
+
+ public final class MetricResultExtensionsKt {
+ method @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public static void assertEqualMeasurements(java.util.List<androidx.benchmark.macro.Metric.Measurement> expected, java.util.List<androidx.benchmark.macro.Metric.Measurement> observed, double threshold);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public enum PowerCategory {
+ method public static androidx.benchmark.macro.PowerCategory valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.PowerCategory[] values();
+ enum_constant public static final androidx.benchmark.macro.PowerCategory CPU;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory DISPLAY;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory GPS;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory GPU;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory MACHINE_LEARNING;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory MEMORY;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory NETWORK;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory UNCATEGORIZED;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public enum PowerCategoryDisplayLevel {
+ method public static androidx.benchmark.macro.PowerCategoryDisplayLevel valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.PowerCategoryDisplayLevel[] values();
+ enum_constant public static final androidx.benchmark.macro.PowerCategoryDisplayLevel BREAKDOWN;
+ enum_constant public static final androidx.benchmark.macro.PowerCategoryDisplayLevel TOTAL;
+ }
+
+ @SuppressCompatibility @RequiresApi(29) @androidx.benchmark.macro.ExperimentalMetricApi public final class PowerMetric extends androidx.benchmark.macro.Metric {
+ ctor public PowerMetric(androidx.benchmark.macro.PowerMetric.Type type);
+ method public static androidx.benchmark.macro.PowerMetric.Type.Battery Battery();
+ method public static androidx.benchmark.macro.PowerMetric.Type.Energy Energy(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ method public static androidx.benchmark.macro.PowerMetric.Type.Power Power(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ field public static final androidx.benchmark.macro.PowerMetric.Companion Companion;
+ }
+
+ public static final class PowerMetric.Companion {
+ method public androidx.benchmark.macro.PowerMetric.Type.Battery Battery();
+ method public androidx.benchmark.macro.PowerMetric.Type.Energy Energy(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ method public androidx.benchmark.macro.PowerMetric.Type.Power Power(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ }
+
+ public abstract static sealed class PowerMetric.Type {
+ method public final java.util.Map<androidx.benchmark.macro.PowerCategory,androidx.benchmark.macro.PowerCategoryDisplayLevel> getCategories();
+ method public final void setCategories(java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel>);
+ property public final java.util.Map<androidx.benchmark.macro.PowerCategory,androidx.benchmark.macro.PowerCategoryDisplayLevel> categories;
+ }
+
+ public static final class PowerMetric.Type.Battery extends androidx.benchmark.macro.PowerMetric.Type {
+ ctor public PowerMetric.Type.Battery();
+ }
+
+ public static final class PowerMetric.Type.Energy extends androidx.benchmark.macro.PowerMetric.Type {
+ ctor public PowerMetric.Type.Energy(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> energyCategories);
+ }
+
+ public static final class PowerMetric.Type.Power extends androidx.benchmark.macro.PowerMetric.Type {
+ ctor public PowerMetric.Type.Power(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> powerCategories);
+ }
+
+ public enum StartupMode {
+ method public static androidx.benchmark.macro.StartupMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.StartupMode[] values();
+ enum_constant public static final androidx.benchmark.macro.StartupMode COLD;
+ enum_constant public static final androidx.benchmark.macro.StartupMode HOT;
+ enum_constant public static final androidx.benchmark.macro.StartupMode WARM;
+ }
+
+ public final class StartupTimingMetric extends androidx.benchmark.macro.Metric {
+ ctor public StartupTimingMetric();
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public abstract class TraceMetric extends androidx.benchmark.macro.Metric {
+ ctor public TraceMetric();
+ method public abstract java.util.List<androidx.benchmark.macro.Metric.Measurement> getResult(androidx.benchmark.macro.Metric.CaptureInfo captureInfo, androidx.benchmark.perfetto.PerfettoTraceProcessor.Session traceSession);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
+ ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
+ }
+
+ public enum TraceSectionMetric.Mode {
+ method public static androidx.benchmark.macro.TraceSectionMetric.Mode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.TraceSectionMetric.Mode[] values();
+ enum_constant public static final androidx.benchmark.macro.TraceSectionMetric.Mode First;
+ enum_constant public static final androidx.benchmark.macro.TraceSectionMetric.Mode Sum;
+ }
+
+}
+
+package androidx.benchmark.perfetto {
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalPerfettoTraceProcessorApi {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi public final class PerfettoTraceProcessor {
+ ctor public PerfettoTraceProcessor();
+ method public <T> T loadTrace(androidx.benchmark.perfetto.PerfettoTrace trace, kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTraceProcessor.Session,? extends T> block);
+ method public static <T> T runServer(kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTraceProcessor,? extends T> block);
+ field public static final androidx.benchmark.perfetto.PerfettoTraceProcessor.Companion Companion;
+ }
+
+ public static final class PerfettoTraceProcessor.Companion {
+ method public <T> T runServer(kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTraceProcessor,? extends T> block);
+ }
+
+ public static final class PerfettoTraceProcessor.Session {
+ method public kotlin.sequences.Sequence<androidx.benchmark.perfetto.Row> query(@org.intellij.lang.annotations.Language("sql") String query);
+ method public byte[] rawQuery(@org.intellij.lang.annotations.Language("sql") String query);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi public final class Row implements kotlin.jvm.internal.markers.KMappedMarker java.util.Map<java.lang.String,java.lang.Object> {
+ ctor public Row(java.util.Map<java.lang.String,?> map);
+ method public byte[] bytes(String columnName);
+ method public double double(String columnName);
+ method public long long(String columnName);
+ method public byte[]? nullableBytes(String columnName);
+ method public Double? nullableDouble(String columnName);
+ method public Long? nullableLong(String columnName);
+ method public String? nullableString(String columnName);
+ method public String string(String columnName);
+ }
+
+ public final class RowKt {
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi public static androidx.benchmark.perfetto.Row rowOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+}
+
diff --git a/benchmark/benchmark-macro/api/current.txt b/benchmark/benchmark-macro/api/current.txt
index 6b770f4..54c8a8c 100644
--- a/benchmark/benchmark-macro/api/current.txt
+++ b/benchmark/benchmark-macro/api/current.txt
@@ -208,7 +208,7 @@
}
@SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
- ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+ ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
}
public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/api/res-1.2.0-beta03.txt b/benchmark/benchmark-macro/api/res-1.2.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/benchmark/benchmark-macro/api/res-1.2.0-beta03.txt
diff --git a/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt b/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt
index 32628f3..9fb21fd 100644
--- a/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt
+++ b/benchmark/benchmark-macro/api/restricted_1.2.0-beta02.txt
@@ -230,7 +230,7 @@
}
@SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
- ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+ ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
}
public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/api/restricted_1.2.0-beta03.txt b/benchmark/benchmark-macro/api/restricted_1.2.0-beta03.txt
new file mode 100644
index 0000000..9fb21fd
--- /dev/null
+++ b/benchmark/benchmark-macro/api/restricted_1.2.0-beta03.txt
@@ -0,0 +1,283 @@
+// Signature format: 4.0
+package androidx.benchmark.macro {
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class AudioUnderrunMetric extends androidx.benchmark.macro.Metric {
+ ctor public AudioUnderrunMetric();
+ }
+
+ public enum BaselineProfileMode {
+ method public static androidx.benchmark.macro.BaselineProfileMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.BaselineProfileMode[] values();
+ enum_constant public static final androidx.benchmark.macro.BaselineProfileMode Disable;
+ enum_constant public static final androidx.benchmark.macro.BaselineProfileMode Require;
+ enum_constant public static final androidx.benchmark.macro.BaselineProfileMode UseIfAvailable;
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class BatteryCharge {
+ method public boolean hasMinimumCharge(optional boolean throwOnMissingMetrics);
+ field public static final androidx.benchmark.macro.BatteryCharge INSTANCE;
+ }
+
+ public abstract sealed class CompilationMode {
+ field public static final androidx.benchmark.macro.CompilationMode.Companion Companion;
+ field public static final androidx.benchmark.macro.CompilationMode DEFAULT;
+ }
+
+ public static final class CompilationMode.Companion {
+ }
+
+ public static final class CompilationMode.Full extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.Full();
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMacrobenchmarkApi public static final class CompilationMode.Ignore extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.Ignore();
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final class CompilationMode.Interpreted extends androidx.benchmark.macro.CompilationMode {
+ field public static final androidx.benchmark.macro.CompilationMode.Interpreted INSTANCE;
+ }
+
+ @RequiresApi(24) public static final class CompilationMode.None extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.None();
+ }
+
+ @RequiresApi(24) public static final class CompilationMode.Partial extends androidx.benchmark.macro.CompilationMode {
+ ctor public CompilationMode.Partial();
+ ctor public CompilationMode.Partial(optional androidx.benchmark.macro.BaselineProfileMode baselineProfileMode);
+ ctor public CompilationMode.Partial(optional androidx.benchmark.macro.BaselineProfileMode baselineProfileMode, optional @IntRange(from=0L) int warmupIterations);
+ method public androidx.benchmark.macro.BaselineProfileMode getBaselineProfileMode();
+ method public int getWarmupIterations();
+ property public final androidx.benchmark.macro.BaselineProfileMode baselineProfileMode;
+ property public final int warmupIterations;
+ }
+
+ public final class CompilationModeKt {
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static boolean isSupportedWithVmSettings(androidx.benchmark.macro.CompilationMode);
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This Macrobenchmark API is experimental.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalMacrobenchmarkApi {
+ }
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(message="This Metric API is experimental.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalMetricApi {
+ }
+
+ public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
+ ctor public FrameTimingMetric();
+ }
+
+ public final class MacrobenchmarkScope {
+ ctor public MacrobenchmarkScope(String packageName, boolean launchWithClearTask);
+ method public void dropKernelPageCache();
+ method public void dropShaderCache();
+ method public androidx.test.uiautomator.UiDevice getDevice();
+ method public Integer? getIteration();
+ method public String getPackageName();
+ method public void killProcess();
+ method public void killProcess(optional boolean useKillAll);
+ method public void pressHome();
+ method public void pressHome(optional long delayDurationMs);
+ method public void startActivityAndWait();
+ method public void startActivityAndWait(android.content.Intent intent);
+ method public void startActivityAndWait(optional kotlin.jvm.functions.Function1<? super android.content.Intent,kotlin.Unit> block);
+ property public final androidx.test.uiautomator.UiDevice device;
+ property public final Integer? iteration;
+ property public final String packageName;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class MemoryCountersMetric extends androidx.benchmark.macro.TraceMetric {
+ ctor public MemoryCountersMetric();
+ method public java.util.List<androidx.benchmark.macro.Metric.Measurement> getResult(androidx.benchmark.macro.Metric.CaptureInfo captureInfo, androidx.benchmark.perfetto.PerfettoTraceProcessor.Session traceSession);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class MemoryUsageMetric extends androidx.benchmark.macro.TraceMetric {
+ ctor public MemoryUsageMetric(androidx.benchmark.macro.MemoryUsageMetric.Mode mode, optional java.util.List<? extends androidx.benchmark.macro.MemoryUsageMetric.SubMetric> subMetrics);
+ method public java.util.List<androidx.benchmark.macro.Metric.Measurement> getResult(androidx.benchmark.macro.Metric.CaptureInfo captureInfo, androidx.benchmark.perfetto.PerfettoTraceProcessor.Session traceSession);
+ }
+
+ public enum MemoryUsageMetric.Mode {
+ method public static androidx.benchmark.macro.MemoryUsageMetric.Mode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.MemoryUsageMetric.Mode[] values();
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.Mode Last;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.Mode Max;
+ }
+
+ public enum MemoryUsageMetric.SubMetric {
+ method public static androidx.benchmark.macro.MemoryUsageMetric.SubMetric valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.MemoryUsageMetric.SubMetric[] values();
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric Gpu;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric HeapSize;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric RssAnon;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric RssFile;
+ enum_constant public static final androidx.benchmark.macro.MemoryUsageMetric.SubMetric RssShmem;
+ }
+
+ public abstract sealed class Metric {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public static final class Metric.CaptureInfo {
+ ctor public Metric.CaptureInfo(int apiLevel, String targetPackageName, String testPackageName, androidx.benchmark.macro.StartupMode? startupMode);
+ method public int component1();
+ method public String component2();
+ method public String component3();
+ method public androidx.benchmark.macro.StartupMode? component4();
+ method public androidx.benchmark.macro.Metric.CaptureInfo copy(int apiLevel, String targetPackageName, String testPackageName, androidx.benchmark.macro.StartupMode? startupMode);
+ method public int getApiLevel();
+ method public androidx.benchmark.macro.StartupMode? getStartupMode();
+ method public String getTargetPackageName();
+ method public String getTestPackageName();
+ property public final int apiLevel;
+ property public final androidx.benchmark.macro.StartupMode? startupMode;
+ property public final String targetPackageName;
+ property public final String testPackageName;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public static final class Metric.Measurement {
+ ctor public Metric.Measurement(String name, double data);
+ ctor public Metric.Measurement(String name, java.util.List<java.lang.Double> dataSamples);
+ method public String component1();
+ method public java.util.List<java.lang.Double> component2();
+ method public boolean component3();
+ method public androidx.benchmark.macro.Metric.Measurement copy(String name, java.util.List<java.lang.Double> data, boolean requireSingleValue);
+ method public java.util.List<java.lang.Double> getData();
+ method public String getName();
+ method public boolean getRequireSingleValue();
+ property public final java.util.List<java.lang.Double> data;
+ property public final String name;
+ property public final boolean requireSingleValue;
+ }
+
+ public final class MetricResultExtensionsKt {
+ method @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public static void assertEqualMeasurements(java.util.List<androidx.benchmark.macro.Metric.Measurement> expected, java.util.List<androidx.benchmark.macro.Metric.Measurement> observed, double threshold);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public enum PowerCategory {
+ method public static androidx.benchmark.macro.PowerCategory valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.PowerCategory[] values();
+ enum_constant public static final androidx.benchmark.macro.PowerCategory CPU;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory DISPLAY;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory GPS;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory GPU;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory MACHINE_LEARNING;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory MEMORY;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory NETWORK;
+ enum_constant public static final androidx.benchmark.macro.PowerCategory UNCATEGORIZED;
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public enum PowerCategoryDisplayLevel {
+ method public static androidx.benchmark.macro.PowerCategoryDisplayLevel valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.PowerCategoryDisplayLevel[] values();
+ enum_constant public static final androidx.benchmark.macro.PowerCategoryDisplayLevel BREAKDOWN;
+ enum_constant public static final androidx.benchmark.macro.PowerCategoryDisplayLevel TOTAL;
+ }
+
+ @SuppressCompatibility @RequiresApi(29) @androidx.benchmark.macro.ExperimentalMetricApi public final class PowerMetric extends androidx.benchmark.macro.Metric {
+ ctor public PowerMetric(androidx.benchmark.macro.PowerMetric.Type type);
+ method public static androidx.benchmark.macro.PowerMetric.Type.Battery Battery();
+ method public static androidx.benchmark.macro.PowerMetric.Type.Energy Energy(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ method public static androidx.benchmark.macro.PowerMetric.Type.Power Power(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ field public static final androidx.benchmark.macro.PowerMetric.Companion Companion;
+ }
+
+ public static final class PowerMetric.Companion {
+ method public androidx.benchmark.macro.PowerMetric.Type.Battery Battery();
+ method public androidx.benchmark.macro.PowerMetric.Type.Energy Energy(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ method public androidx.benchmark.macro.PowerMetric.Type.Power Power(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> categories);
+ }
+
+ public abstract static sealed class PowerMetric.Type {
+ method public final java.util.Map<androidx.benchmark.macro.PowerCategory,androidx.benchmark.macro.PowerCategoryDisplayLevel> getCategories();
+ method public final void setCategories(java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel>);
+ property public final java.util.Map<androidx.benchmark.macro.PowerCategory,androidx.benchmark.macro.PowerCategoryDisplayLevel> categories;
+ }
+
+ public static final class PowerMetric.Type.Battery extends androidx.benchmark.macro.PowerMetric.Type {
+ ctor public PowerMetric.Type.Battery();
+ }
+
+ public static final class PowerMetric.Type.Energy extends androidx.benchmark.macro.PowerMetric.Type {
+ ctor public PowerMetric.Type.Energy(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> energyCategories);
+ }
+
+ public static final class PowerMetric.Type.Power extends androidx.benchmark.macro.PowerMetric.Type {
+ ctor public PowerMetric.Type.Power(optional java.util.Map<androidx.benchmark.macro.PowerCategory,? extends androidx.benchmark.macro.PowerCategoryDisplayLevel> powerCategories);
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class PowerRail {
+ method public boolean hasMetrics(optional boolean throwOnMissingMetrics);
+ field public static final androidx.benchmark.macro.PowerRail INSTANCE;
+ }
+
+ public enum StartupMode {
+ method public static androidx.benchmark.macro.StartupMode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.StartupMode[] values();
+ enum_constant public static final androidx.benchmark.macro.StartupMode COLD;
+ enum_constant public static final androidx.benchmark.macro.StartupMode HOT;
+ enum_constant public static final androidx.benchmark.macro.StartupMode WARM;
+ }
+
+ @RequiresApi(29) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class StartupTimingLegacyMetric extends androidx.benchmark.macro.Metric {
+ ctor public StartupTimingLegacyMetric();
+ }
+
+ public final class StartupTimingMetric extends androidx.benchmark.macro.Metric {
+ ctor public StartupTimingMetric();
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public abstract class TraceMetric extends androidx.benchmark.macro.Metric {
+ ctor public TraceMetric();
+ method public abstract java.util.List<androidx.benchmark.macro.Metric.Measurement> getResult(androidx.benchmark.macro.Metric.CaptureInfo captureInfo, androidx.benchmark.perfetto.PerfettoTraceProcessor.Session traceSession);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
+ ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
+ }
+
+ public enum TraceSectionMetric.Mode {
+ method public static androidx.benchmark.macro.TraceSectionMetric.Mode valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.benchmark.macro.TraceSectionMetric.Mode[] values();
+ enum_constant public static final androidx.benchmark.macro.TraceSectionMetric.Mode First;
+ enum_constant public static final androidx.benchmark.macro.TraceSectionMetric.Mode Sum;
+ }
+
+}
+
+package androidx.benchmark.perfetto {
+
+ @SuppressCompatibility @kotlin.RequiresOptIn @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface ExperimentalPerfettoTraceProcessorApi {
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi public final class PerfettoTraceProcessor {
+ ctor public PerfettoTraceProcessor();
+ method public <T> T loadTrace(androidx.benchmark.perfetto.PerfettoTrace trace, kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTraceProcessor.Session,? extends T> block);
+ method public static <T> T runServer(kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTraceProcessor,? extends T> block);
+ field public static final androidx.benchmark.perfetto.PerfettoTraceProcessor.Companion Companion;
+ }
+
+ public static final class PerfettoTraceProcessor.Companion {
+ method public <T> T runServer(kotlin.jvm.functions.Function1<? super androidx.benchmark.perfetto.PerfettoTraceProcessor,? extends T> block);
+ }
+
+ public static final class PerfettoTraceProcessor.Session {
+ method public kotlin.sequences.Sequence<androidx.benchmark.perfetto.Row> query(@org.intellij.lang.annotations.Language("sql") String query);
+ method public byte[] rawQuery(@org.intellij.lang.annotations.Language("sql") String query);
+ }
+
+ @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi public final class Row implements kotlin.jvm.internal.markers.KMappedMarker java.util.Map<java.lang.String,java.lang.Object> {
+ ctor public Row(java.util.Map<java.lang.String,?> map);
+ method public byte[] bytes(String columnName);
+ method public double double(String columnName);
+ method public long long(String columnName);
+ method public byte[]? nullableBytes(String columnName);
+ method public Double? nullableDouble(String columnName);
+ method public Long? nullableLong(String columnName);
+ method public String? nullableString(String columnName);
+ method public String string(String columnName);
+ }
+
+ public final class RowKt {
+ method @SuppressCompatibility @androidx.benchmark.perfetto.ExperimentalPerfettoTraceProcessorApi public static androidx.benchmark.perfetto.Row rowOf(kotlin.Pair<java.lang.String,?>... pairs);
+ }
+
+}
+
diff --git a/benchmark/benchmark-macro/api/restricted_current.txt b/benchmark/benchmark-macro/api/restricted_current.txt
index 32628f3..9fb21fd 100644
--- a/benchmark/benchmark-macro/api/restricted_current.txt
+++ b/benchmark/benchmark-macro/api/restricted_current.txt
@@ -230,7 +230,7 @@
}
@SuppressCompatibility @androidx.benchmark.macro.ExperimentalMetricApi public final class TraceSectionMetric extends androidx.benchmark.macro.Metric {
- ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode);
+ ctor public TraceSectionMetric(String sectionName, optional androidx.benchmark.macro.TraceSectionMetric.Mode mode, optional boolean targetPackageOnly);
}
public enum TraceSectionMetric.Mode {
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
index 03de19f..09a6c7d 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkTest.kt
@@ -96,7 +96,8 @@
className = "MacrobenchmarkTest",
testName = "validateCallbackBehavior",
packageName = Packages.TARGET,
- metrics = listOf(TraceSectionMetric(TRACE_LABEL)),
+ // disable targetPackageOnly filter, since this process emits the event
+ metrics = listOf(TraceSectionMetric(TRACE_LABEL, targetPackageOnly = false)),
compilationMode = CompilationMode.DEFAULT,
iterations = 2,
startupMode = startupMode,
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt
index b8b2819..d5229ca 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/PerfettoTraceRuleTest.kt
@@ -58,7 +58,7 @@
val sliceNameInstances = PerfettoTraceProcessor.runSingleSessionServer(
trace!!.path
) {
- querySlices(UNIQUE_SLICE_NAME)
+ querySlices(UNIQUE_SLICE_NAME, packageName = null)
.map { slice -> slice.name }
}
assertEquals(listOf(UNIQUE_SLICE_NAME), sliceNameInstances)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
index 4eedd27..d69c472 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/TraceSectionMetricTest.kt
@@ -38,7 +38,7 @@
@Test
fun activityThreadMain() = verifyFirstSum(
tracePath = api24ColdStart,
- packageName = Packages.TEST,
+ packageName = Packages.TARGET,
sectionName = "ActivityThreadMain",
expectedFirstMs = 12.639
)
@@ -46,7 +46,7 @@
@Test
fun activityStart() = verifyFirstSum(
tracePath = api24ColdStart,
- packageName = Packages.TEST,
+ packageName = Packages.TARGET,
sectionName = "activityStart",
expectedFirstMs = 81.979
)
@@ -54,17 +54,18 @@
@Test
fun startActivityAndWait() = verifyFirstSum(
tracePath = api24ColdStart,
- packageName = Packages.TEST,
+ packageName = "androidx.benchmark.integration.macrobenchmark.test",
sectionName = "startActivityAndWait",
- expectedFirstMs = 1_110.689
+ expectedFirstMs = 1_110.689,
)
@Test
fun launching() = verifyFirstSum(
tracePath = api24ColdStart,
- packageName = Packages.TEST,
+ packageName = Packages.TARGET,
sectionName = "launching: androidx.benchmark.integration.macrobenchmark.target",
- expectedFirstMs = 269.947
+ expectedFirstMs = 269.947,
+ targetPackageOnly = false // slice from system_server
)
@Test
@@ -76,23 +77,28 @@
)
@Test
- fun multiSection() = verifyFirstSum(
+ fun multiSection_targetOnly() = verifyFirstSum(
+ tracePath = api24ColdStart,
+ packageName = Packages.TARGET,
+ sectionName = "inflate",
+ expectedFirstMs = 4.949, // first inflation
+ expectedSumMs = 19.779, // total inflation
+ expectedSumCount = 3,
+ targetPackageOnly = true,
+ )
+
+ @Test
+ fun multiSection_unfiltered() = verifyFirstSum(
tracePath = api24ColdStart,
packageName = Packages.TARGET,
sectionName = "inflate",
expectedFirstMs = 13.318, // first inflation
expectedSumMs = 43.128, // total inflation
expectedSumCount = 8,
+ targetPackageOnly = false,
)
companion object {
- private val captureInfo = Metric.CaptureInfo(
- targetPackageName = Packages.TEST,
- testPackageName = Packages.TEST,
- startupMode = StartupMode.COLD,
- apiLevel = 24
- )
-
private fun verifyMetric(
tracePath: String,
packageName: String,
@@ -100,15 +106,23 @@
mode: TraceSectionMetric.Mode,
expectedMs: Double,
expectedCount: Int,
+ targetPackageOnly: Boolean
) {
assumeTrue(PerfettoHelper.isAbiSupported())
- val metric = TraceSectionMetric(sectionName, mode)
+ val metric = TraceSectionMetric(sectionName, mode, targetPackageOnly)
metric.configure(packageName = packageName)
val result = PerfettoTraceProcessor.runSingleSessionServer(tracePath) {
metric.getResult(
- captureInfo = captureInfo,
+ // note that most args are incorrect here, but currently
+ // only targetPackageName matters in this context
+ captureInfo = Metric.CaptureInfo(
+ targetPackageName = packageName,
+ testPackageName = Packages.TEST,
+ startupMode = StartupMode.COLD,
+ apiLevel = 24
+ ),
traceSession = this
)
}
@@ -134,7 +148,8 @@
sectionName: String,
expectedFirstMs: Double,
expectedSumMs: Double = expectedFirstMs, // default implies only one matching section
- expectedSumCount: Int = 1
+ expectedSumCount: Int = 1,
+ targetPackageOnly: Boolean = true,
) {
verifyMetric(
tracePath = tracePath,
@@ -142,7 +157,8 @@
sectionName = sectionName,
mode = TraceSectionMetric.Mode.First,
expectedMs = expectedFirstMs,
- expectedCount = 1
+ expectedCount = 1,
+ targetPackageOnly = targetPackageOnly,
)
verifyMetric(
tracePath = tracePath,
@@ -151,6 +167,7 @@
mode = TraceSectionMetric.Mode.Sum,
expectedMs = expectedSumMs,
expectedCount = expectedSumCount,
+ targetPackageOnly = targetPackageOnly,
)
}
}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt
index db3bea2..31de56f 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/BatteryDischargeQueryTest.kt
@@ -42,7 +42,8 @@
val traceFile = createTempFileFromAsset("api31_battery_discharge", ".perfetto-trace")
val actualMetrics = PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
- val slice = querySlices(PowerMetric.MEASURE_BLOCK_SECTION_NAME).first()
+ val slice =
+ querySlices(PowerMetric.MEASURE_BLOCK_SECTION_NAME, packageName = null).first()
BatteryDischargeQuery.getBatteryDischargeMetrics(this, slice)
}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
index 117726f..41d9868 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureSweepTest.kt
@@ -129,7 +129,7 @@
perfettoCapture.stop(traceFilePath)
val matchingSlices = PerfettoTraceProcessor.runSingleSessionServer(traceFilePath) {
- querySlices("PerfettoCaptureTest_%")
+ querySlices("PerfettoCaptureTest_%", packageName = null)
}
// Note: this test avoids validating platform-triggered trace sections, to avoid flakes
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
index f8cbebb..0bcb3b4 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkHandshakeTest.kt
@@ -43,7 +43,6 @@
import org.junit.After
import org.junit.Assume.assumeTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -216,14 +215,10 @@
}
}
- // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
- @Ignore
@Test
fun test_handshake_framework_cold_start_persistent() =
test_handshake_framework_cold_start(persistent = true)
- // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
- @Ignore
@Test
fun test_handshake_framework_cold_start_non_persistent() =
test_handshake_framework_cold_start(persistent = false)
@@ -277,8 +272,6 @@
}
}
- // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
- @Ignore
/**
* Tests [androidx.benchmark.perfetto.PerfettoCapture.enableAndroidxTracingPerfetto] as
* opposed to [androidx.tracing.perfetto.handshake.PerfettoSdkHandshake.enableTracingColdStart]
@@ -326,14 +319,10 @@
}
}
- // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
- @Ignore
@Test
fun test_handshake_framework_cold_start_disable_persistent() =
test_handshake_framework_cold_start_disable(persistent = true)
- // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
- @Ignore
@Test
fun test_handshake_framework_cold_start_disable_non_persistent() =
test_handshake_framework_cold_start_disable(persistent = true)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt
index 07c1416..d171aaa 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoSdkTraceTest.kt
@@ -58,7 +58,12 @@
if (enableUserspaceTracing) yield(StringSource.userspaceTraceStrings)
}.flatMap { it }.toList()
val actualSlices = PerfettoTraceProcessor.runSingleSessionServer(trace.path) {
- StringSource.allTraceStrings.flatMap { querySlices(it).map { s -> s.name } }
+ StringSource.allTraceStrings.flatMap {
+ querySlices(
+ it,
+ packageName = null
+ ).map { s -> s.name }
+ }
}
assertThat(actualSlices).containsExactlyElementsIn(expectedSlices)
}
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt
index c3e4847..4c5e491 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PowerQueryTest.kt
@@ -43,7 +43,7 @@
val actualMetrics = PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
PowerQuery.getPowerMetrics(
this,
- querySlices(MEASURE_BLOCK_SECTION_NAME).first()
+ querySlices(MEASURE_BLOCK_SECTION_NAME, packageName = null).first()
)
}
@@ -182,7 +182,10 @@
val traceFile = createTempFileFromAsset("api31_odpm_rails_empty", ".perfetto-trace")
val actualMetrics = PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
- PowerQuery.getPowerMetrics(this, querySlices(MEASURE_BLOCK_SECTION_NAME).first())
+ PowerQuery.getPowerMetrics(
+ this,
+ querySlices(MEASURE_BLOCK_SECTION_NAME, packageName = null).first()
+ )
}
assertEquals(emptyMap(), actualMetrics)
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
index e772ff9..37769a6 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/perfetto/PerfettoTraceProcessorTest.kt
@@ -21,7 +21,8 @@
import androidx.benchmark.macro.createTempFileFromAsset
import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
+import androidx.test.filters.LargeTest
+import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry
import java.io.File
import java.net.ConnectException
@@ -37,7 +38,7 @@
import org.junit.Test
import org.junit.runner.RunWith
-@SmallTest
+@MediumTest
@RunWith(AndroidJUnit4::class)
class PerfettoTraceProcessorTest {
@Test
@@ -93,38 +94,66 @@
}
}
+ enum class QuerySlicesMode(val target: String?) {
+ ValidPackage("androidx.benchmark.integration.macrobenchmark.target"),
+ Unspecified(null),
+ InvalidPackage("not.a.real.package")
+ }
+
@Test
- fun querySlices() {
+ fun querySlices_validPackage() = validateQuerySlices(QuerySlicesMode.ValidPackage)
+
+ @Test
+ fun querySlices_invalidPackage() = validateQuerySlices(QuerySlicesMode.InvalidPackage)
+
+ @Test
+ fun querySlices_unspecified() = validateQuerySlices(QuerySlicesMode.Unspecified)
+
+ private fun validateQuerySlices(mode: QuerySlicesMode) {
// check known slice content is queryable
assumeTrue(isAbiSupported())
val traceFile = createTempFileFromAsset("api31_startup_cold", ".perfetto-trace")
PerfettoTraceProcessor.runSingleSessionServer(traceFile.absolutePath) {
assertEquals(
- expected = listOf(
- Slice(
- name = "activityStart",
- ts = 186975009436431,
- dur = 29580628
+ expected = when (mode) {
+ QuerySlicesMode.InvalidPackage -> emptyList()
+ else -> listOf(
+ Slice(
+ name = "activityStart",
+ ts = 186975009436431,
+ dur = 29580628
+ )
)
- ),
- actual = querySlices("activityStart")
+ },
+ actual = querySlices("activityStart", packageName = mode.target)
)
assertEquals(
- expected = listOf(
- Slice(
- name = "activityStart",
- ts = 186975009436431,
- dur = 29580628
- ),
- Slice(
- name = "activityResume",
- ts = 186975039764298,
- dur = 6570418
+ expected = when (mode) {
+ QuerySlicesMode.InvalidPackage -> emptyList()
+ else -> listOf(
+ Slice(
+ name = "activityStart",
+ ts = 186975009436431,
+ dur = 29580628
+ ),
+ Slice(
+ name = "activityResume",
+ ts = 186975039764298,
+ dur = 6570418
+ )
)
- ),
- actual = querySlices("activityStart", "activityResume")
+ },
+ actual = querySlices("activityStart", "activityResume", packageName = mode.target)
.sortedBy { it.ts }
)
+ assertEquals(
+ expected = when (mode) {
+ QuerySlicesMode.ValidPackage -> 7
+ QuerySlicesMode.Unspecified -> 127
+ QuerySlicesMode.InvalidPackage -> 0
+ },
+ actual = querySlices("Lock contention %", packageName = mode.target).size
+ )
}
}
@@ -253,6 +282,7 @@
assertTrue(!isRunning())
}
+ @LargeTest
@Test
fun parseLongTrace() {
val traceFile = File
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
index cc75044..bb55014 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/BaselineProfiles.kt
@@ -27,7 +27,7 @@
import androidx.benchmark.InstrumentationResults
import androidx.benchmark.Outputs
import androidx.benchmark.Shell
-import androidx.benchmark.userspaceTrace
+import androidx.benchmark.inMemoryTrace
import java.io.File
/**
@@ -59,7 +59,7 @@
val finalMaxIterations = if (Arguments.dryRunMode) 1 else maxIterations
while (iteration <= finalMaxIterations) {
- userspaceTrace("generate profile for $packageName ($iteration)") {
+ inMemoryTrace("generate profile for $packageName ($iteration)") {
val mode = CompilationMode.Partial(
baselineProfileMode = BaselineProfileMode.Disable,
warmupIterations = 1
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
index 1b9da10..4aecd9b 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/CompilationMode.kt
@@ -24,11 +24,11 @@
import androidx.benchmark.Arguments
import androidx.benchmark.DeviceInfo
import androidx.benchmark.Shell
+import androidx.benchmark.inMemoryTrace
import androidx.benchmark.macro.CompilationMode.Full
import androidx.benchmark.macro.CompilationMode.Ignore
import androidx.benchmark.macro.CompilationMode.None
import androidx.benchmark.macro.CompilationMode.Partial
-import androidx.benchmark.userspaceTrace
import androidx.profileinstaller.ProfileInstallReceiver
import org.junit.AssumptionViolatedException
@@ -123,7 +123,7 @@
* does work on older APIs without root
*/
private fun reinstallPackage(packageName: String) {
- userspaceTrace("reinstallPackage") {
+ inMemoryTrace("reinstallPackage") {
// Copy APKs to /data/local/temp
val apkPaths = Shell.pmPath(packageName)
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
index 919dc78..df00a1a 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
@@ -30,9 +30,9 @@
import androidx.benchmark.Profiler
import androidx.benchmark.ResultWriter
import androidx.benchmark.Shell
-import androidx.benchmark.UserspaceTracing
import androidx.benchmark.checkAndGetSuppressionState
import androidx.benchmark.conditionalError
+import androidx.benchmark.inMemoryTrace
import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig
import androidx.benchmark.perfetto.PerfettoCapture.PerfettoSdkConfig.InitialProcessState
import androidx.benchmark.perfetto.PerfettoCaptureWrapper
@@ -41,7 +41,6 @@
import androidx.benchmark.perfetto.PerfettoTraceProcessor
import androidx.benchmark.perfetto.UiState
import androidx.benchmark.perfetto.appendUiState
-import androidx.benchmark.userspaceTrace
import androidx.test.platform.app.InstrumentationRegistry
import androidx.tracing.trace
import java.io.File
@@ -67,12 +66,6 @@
val applicationInfo = getInstalledPackageInfo(packageName)
- val errorNotProfileable = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- applicationInfo.isNotProfileableByShell()
- } else {
- false
- }
-
val instrumentation = InstrumentationRegistry.getInstrumentation()
val errors = DeviceInfo.errors +
// TODO: Merge this debuggable check / definition with Errors.kt in benchmark-common
@@ -82,23 +75,27 @@
id = "DEBUGGABLE",
summary = "Benchmark Target is Debuggable",
message = """
- Target package $packageName
- is running with debuggable=true, which drastically reduces
- runtime performance in order to support debugging features. Run
- benchmarks with debuggable=false. Debuggable affects execution speed
- in ways that mean benchmark improvements might not carry over to a
+ Target package $packageName is running with debuggable=true in its manifest,
+ which drastically reduces runtime performance in order to support debugging
+ features. Run benchmarks with debuggable=false. Debuggable affects execution
+ speed in ways that mean benchmark improvements might not carry over to a
real user's experience (or even regress release performance).
""".trimIndent()
),
conditionalError(
- hasError = errorNotProfileable,
+ // Profileable is currently only needed on API 29+30, since app trace tag no longer
+ // requires profileable on API 31, and macrobench doesn't currently offer other
+ // means of profiling (like simpleperf) that need the flag.
+ hasError = DeviceInfo.profileableEnforced &&
+ Build.VERSION.SDK_INT in 29..30 &&
+ applicationInfo.isNotProfileableByShell(),
id = "NOT-PROFILEABLE",
summary = "Benchmark Target is NOT profileable",
message = """
- Target package $packageName
- is running without profileable. Profileable is required to enable
- macrobenchmark to capture detailed trace information from the target process,
- such as System tracing sections defined in the app, or libraries.
+ Target package $packageName is running without <profileable shell=true>.
+ Profileable is required on Android 10 & 11 to enable macrobenchmark to capture
+ detailed trace information from the target process, such as System tracing
+ sections defined in the app, or libraries.
To make the target profileable, add the following in your target app's
main AndroidManifest.xml, within the application tag:
@@ -222,7 +219,7 @@
// Always kill the process at beginning of test
scope.killProcess()
- userspaceTrace("compile $packageName") {
+ inMemoryTrace("compile $packageName") {
compilationMode.resetAndCompile(packageName, killProcessBlock = scope::killProcess) {
setupBlock(scope)
measureBlock(scope)
@@ -245,12 +242,12 @@
val runIterations = if (Arguments.dryRunMode) 1 else iterations
List(runIterations) { iteration ->
// Wake the device to ensure it stays awake with large iteration count
- userspaceTrace("wake device") {
+ inMemoryTrace("wake device") {
scope.device.wakeUp()
}
scope.iteration = iteration
- userspaceTrace("setupBlock") {
+ inMemoryTrace("setupBlock") {
setupBlock(scope)
}
@@ -276,7 +273,8 @@
},
useStackSamplingConfig = true
),
- perfettoSdkConfig = perfettoSdkConfig
+ perfettoSdkConfig = perfettoSdkConfig,
+ inMemoryTracingLabel = "Macrobenchmark"
) {
try {
trace("start metrics") {
@@ -308,7 +306,7 @@
val measurementList = loadTrace(PerfettoTrace(tracePath)) {
// Extracts the metrics using the perfetto trace processor
- userspaceTrace("extract metrics") {
+ inMemoryTrace("extract metrics") {
metrics
// capture list of Measurements
.map {
@@ -332,10 +330,6 @@
highlightPackage = packageName
)
File(tracePath).apply {
- // Disabled currently, see b/194424816 and b/174007010
- // appendBytes(UserspaceTracing.commitToTrace().encode())
- UserspaceTracing.commitToTrace() // clear buffer
-
appendUiState(uiState)
}
Log.d(TAG, "Iteration $iteration captured $uiState")
@@ -408,7 +402,7 @@
measureBlock: MacrobenchmarkScope.() -> Unit
) {
val perfettoSdkConfig =
- if (Arguments.fullTracingEnable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ if (Arguments.perfettoSdkTracingEnable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
PerfettoSdkConfig(
packageName,
when (startupMode) {
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
index 7a07561..f77efc40e 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/MethodTracing.kt
@@ -5,7 +5,7 @@
import androidx.benchmark.Outputs
import androidx.benchmark.Shell
import androidx.benchmark.getFirstMountedMediaDir
-import androidx.benchmark.userspaceTrace
+import androidx.benchmark.inMemoryTrace
import androidx.test.platform.app.InstrumentationRegistry
import java.io.File
@@ -73,7 +73,7 @@
}
private fun broadcast(targetPackageName: String, extras: String) {
- userspaceTrace("methodTracingBroadcast") {
+ inMemoryTrace("methodTracingBroadcast") {
val action = "androidx.benchmark.experiments.ACTION_METHOD_TRACE"
val result =
Shell.amBroadcast("-a $action $extras $targetPackageName/$RECEIVER_NAME") ?: 0
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
index e60b36a..4b3ba98 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
@@ -382,7 +382,8 @@
* Captures the time taken by named trace section - a named begin / end pair matching the provided
* [sectionName].
*
- * Select how matching sections are resolved into a duration metric with [mode].
+ * Select how matching sections are resolved into a duration metric with [mode], and configure if
+ * sections outside the target process are included with [targetPackageOnly].
*
* @see androidx.tracing.Trace.beginSection
* @see androidx.tracing.Trace.endSection
@@ -390,8 +391,22 @@
*/
@ExperimentalMetricApi
class TraceSectionMetric(
+ /**
+ * Section name or pattern to match.
+ *
+ * "%" can be used as a wildcard, as this is supported by the underlying
+ * [PerfettoTraceProcessor] query. For example `"JIT %"` will match a section named
+ * `"JIT compiling int com.package.MyClass.method(int)"` present in the trace.
+ */
private val sectionName: String,
- private val mode: Mode = Mode.First
+ /**
+ * How should the
+ */
+ private val mode: Mode = Mode.First,
+ /**
+ * Filter results to trace sections only from the target process, defaults to true.
+ */
+ private val targetPackageOnly: Boolean = true
) : Metric() {
enum class Mode {
/**
@@ -425,7 +440,10 @@
captureInfo: CaptureInfo,
traceSession: PerfettoTraceProcessor.Session
): List<Measurement> {
- val slices = traceSession.querySlices(sectionName)
+ val slices = traceSession.querySlices(
+ sectionName,
+ packageName = if (targetPackageOnly) captureInfo.targetPackageName else null
+ )
return when (mode) {
Mode.First -> {
@@ -583,7 +601,7 @@
traceSession: PerfettoTraceProcessor.Session
): List<Measurement> {
// collect metrics between trace point flags
- val slice = traceSession.querySlices(MEASURE_BLOCK_SECTION_NAME)
+ val slice = traceSession.querySlices(MEASURE_BLOCK_SECTION_NAME, packageName = null)
.firstOrNull()
?: return emptyList()
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
index 2f74b4c..4fd7b50 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/server/PerfettoHttpServer.kt
@@ -24,8 +24,8 @@
import androidx.annotation.RequiresApi
import androidx.benchmark.Shell
import androidx.benchmark.ShellScript
+import androidx.benchmark.inMemoryTrace
import androidx.benchmark.perfetto.PerfettoTraceProcessor
-import androidx.benchmark.userspaceTrace
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
@@ -101,10 +101,10 @@
* @throws IllegalStateException if the server is not running by the end of the timeout.
*/
@SuppressLint("BanThreadSleep")
- fun startServer() = userspaceTrace("PerfettoHttpServer#startServer") {
+ fun startServer() = inMemoryTrace("PerfettoHttpServer#startServer") {
if (processId != null) {
Log.w(TAG, "Tried to start a trace shell processor that is already running.")
- return@userspaceTrace
+ return@inMemoryTrace
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
@@ -168,10 +168,10 @@
/**
* Stops the server killing the associated process
*/
- fun stopServer() = userspaceTrace("PerfettoHttpServer#stopServer") {
+ fun stopServer() = inMemoryTrace("PerfettoHttpServer#stopServer") {
if (processId == null) {
Log.w(TAG, "Tried to stop trace shell processor http server without starting it.")
- return@userspaceTrace
+ return@inMemoryTrace
}
Shell.executeScriptSilent("kill -TERM $processId")
Log.i(TAG, "Perfetto trace processor shell server stopped (pid=$processId).")
@@ -180,10 +180,10 @@
/**
* Returns true whether the server is running, false otherwise.
*/
- fun isRunning(): Boolean = userspaceTrace("PerfettoHttpServer#isRunning") {
- return@userspaceTrace try {
+ fun isRunning(): Boolean = inMemoryTrace("PerfettoHttpServer#isRunning") {
+ return@inMemoryTrace try {
val statusResult = status()
- return@userspaceTrace statusResult.api_version != null && statusResult.api_version > 0
+ return@inMemoryTrace statusResult.api_version != null && statusResult.api_version > 0
} catch (e: ConnectException) {
false
}
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
index 9314bde..c5bc405 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/perfetto/PerfettoTraceProcessor.kt
@@ -18,8 +18,8 @@
import androidx.annotation.RestrictTo
import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+import androidx.benchmark.inMemoryTrace
import androidx.benchmark.macro.perfetto.server.PerfettoHttpServer
-import androidx.benchmark.userspaceTrace
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
@@ -93,7 +93,7 @@
@JvmStatic
fun <T> runServer(
block: PerfettoTraceProcessor.() -> T
- ): T = userspaceTrace("PerfettoTraceProcessor#runServer") {
+ ): T = inMemoryTrace("PerfettoTraceProcessor#runServer") {
var perfettoTraceProcessor: PerfettoTraceProcessor? = null
try {
@@ -101,7 +101,7 @@
perfettoTraceProcessor = PerfettoTraceProcessor().startServer()
// Executes the query block
- return@userspaceTrace userspaceTrace("PerfettoTraceProcessor#runServer#block") {
+ return@inMemoryTrace inMemoryTrace("PerfettoTraceProcessor#runServer#block") {
block(perfettoTraceProcessor)
}
} finally {
@@ -145,7 +145,7 @@
*/
@RestrictTo(LIBRARY_GROUP) // avoids exposing Proto API
fun getTraceMetrics(metric: String): TraceMetrics {
- userspaceTrace("PerfettoTraceProcessor#getTraceMetrics $metric") {
+ inMemoryTrace("PerfettoTraceProcessor#getTraceMetrics $metric") {
require(!metric.contains(" ")) {
"Metric must not contain spaces: $metric"
}
@@ -186,7 +186,7 @@
* @see PerfettoTraceProcessor.Session
*/
fun query(@Language("sql") query: String): Sequence<Row> {
- userspaceTrace("PerfettoTraceProcessor#query $query".take(127)) {
+ inMemoryTrace("PerfettoTraceProcessor#query $query".take(127)) {
require(traceProcessor.perfettoHttpServer.isRunning()) {
"Perfetto trace_shell_process is not running."
}
@@ -224,7 +224,7 @@
* @see Session.query
*/
fun rawQuery(@Language("sql") query: String): ByteArray {
- userspaceTrace("PerfettoTraceProcessor#query $query".take(127)) {
+ inMemoryTrace("PerfettoTraceProcessor#query $query".take(127)) {
require(traceProcessor.perfettoHttpServer.isRunning()) {
"Perfetto trace_shell_process is not running."
}
@@ -238,21 +238,43 @@
* Note that sliceNames may include wildcard matches, such as `foo%`
*/
@RestrictTo(LIBRARY_GROUP) // Slice API not currently exposed, since it doesn't track table
- fun querySlices(vararg sliceNames: String): List<Slice> {
+ fun querySlices(
+ vararg sliceNames: String,
+ packageName: String?,
+ ): List<Slice> {
require(traceProcessor.perfettoHttpServer.isRunning()) {
"Perfetto trace_shell_process is not running."
}
val whereClause = sliceNames
- .joinToString(separator = " OR ") {
+ .joinToString(
+ separator = " OR ",
+ prefix = if (packageName == null) {
+ "("
+ } else {
+ processNameLikePkg(packageName) + " AND ("
+ },
+ postfix = ")"
+ ) {
"slice.name LIKE \"$it\""
}
+ val innerJoins = if (packageName != null) {
+ """
+ INNER JOIN thread_track on slice.track_id = thread_track.id
+ INNER JOIN thread USING(utid)
+ INNER JOIN process USING(upid)
+ """.trimMargin()
+ } else {
+ ""
+ }
return query(
query = """
SELECT slice.name,ts,dur
FROM slice
+ $innerJoins
WHERE $whereClause
+ ORDER BY ts
""".trimMargin()
).toSlices()
}
@@ -262,13 +284,13 @@
private var traceLoaded = false
private fun startServer(): PerfettoTraceProcessor =
- userspaceTrace("PerfettoTraceProcessor#startServer") {
+ inMemoryTrace("PerfettoTraceProcessor#startServer") {
println("startserver")
perfettoHttpServer.startServer()
- return@userspaceTrace this
+ return@inMemoryTrace this
}
- private fun stopServer() = userspaceTrace("PerfettoTraceProcessor#stopServer") {
+ private fun stopServer() = inMemoryTrace("PerfettoTraceProcessor#stopServer") {
println("stopserver")
perfettoHttpServer.stopServer()
}
@@ -278,7 +300,7 @@
* trace if existing.
*/
private fun loadTraceImpl(absoluteTracePath: String) {
- userspaceTrace("PerfettoTraceProcessor#loadTraceImpl") {
+ inMemoryTrace("PerfettoTraceProcessor#loadTraceImpl") {
require(!absoluteTracePath.contains(" ")) {
"Trace path must not contain spaces: $absoluteTracePath"
}
@@ -306,7 +328,7 @@
/**
* Clears the current loaded trace.
*/
- private fun clearTrace() = userspaceTrace("PerfettoTraceProcessor#clearTrace") {
+ private fun clearTrace() = inMemoryTrace("PerfettoTraceProcessor#clearTrace") {
perfettoHttpServer.restoreInitialTables()
traceLoaded = false
}
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
index 8fb6552..34276ac 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricAdvertiseTest.kt
@@ -50,7 +50,7 @@
* the legacy advertise limit (31 bytes)
*/
@Test
- fun advertiseTooLargeDataO() = runTest {
+ fun advertiseTooLargeData() = runTest {
val parcelUuid = UUID.randomUUID()
val serviceData = "sampleAdvertiseDataTooLargeToAdvertise".toByteArray(Charsets.UTF_8)
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt
new file mode 100644
index 0000000..dddad2d
--- /dev/null
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricGattClientTest.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.bluetooth.testing
+
+import android.bluetooth.BluetoothAdapter
+import android.bluetooth.BluetoothDevice as FwkDevice
+import android.bluetooth.BluetoothGatt
+import android.bluetooth.BluetoothGattCallback
+import android.bluetooth.BluetoothGattCharacteristic
+import android.bluetooth.BluetoothGattDescriptor
+import android.bluetooth.BluetoothGattService
+import android.bluetooth.BluetoothManager
+import android.content.Context
+import androidx.bluetooth.BluetoothDevice
+import androidx.bluetooth.BluetoothLe
+import androidx.bluetooth.GattClient
+import java.util.UUID
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.RuntimeEnvironment
+import org.robolectric.Shadows.shadowOf
+import org.robolectric.shadows.ShadowBluetoothGatt
+
+@RunWith(RobolectricTestRunner::class)
+@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+class RobolectricGattClientTest {
+ private val context: Context = RuntimeEnvironment.getApplication()
+ private val bluetoothManager: BluetoothManager =
+ context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
+ private val bluetoothAdapter: BluetoothAdapter? = bluetoothManager.adapter
+ private lateinit var bluetoothLe: BluetoothLe
+ private lateinit var clientAdapter: StubClientFrameworkAdapter
+
+ private companion object {
+ private val serviceUuid1 = UUID.fromString("00001111-0000-1000-8000-00805F9B34FB")
+ private val serviceUuid2 = UUID.fromString("00001112-0000-1000-8000-00805F9B34FB")
+
+ private val service1 = BluetoothGattService(serviceUuid1,
+ BluetoothGattService.SERVICE_TYPE_PRIMARY)
+ private val service2 = BluetoothGattService(serviceUuid2,
+ BluetoothGattService.SERVICE_TYPE_PRIMARY)
+
+ private val sampleServices: List<BluetoothGattService> = listOf(service1, service2)
+ }
+
+ @Before
+ fun setUp() {
+ bluetoothLe = BluetoothLe(context)
+ clientAdapter = StubClientFrameworkAdapter(bluetoothLe.client.fwkAdapter)
+ bluetoothLe.client.fwkAdapter = clientAdapter
+ }
+
+ @Test
+ fun connectGatt() = runTest {
+ acceptConnect()
+ val device = createDevice("00:11:22:33:44:55")
+ Assert.assertEquals(true, bluetoothLe.connectGatt(device) {
+ Assert.assertEquals(sampleServices.size, getServices().size)
+ sampleServices.forEachIndexed { index, service ->
+ Assert.assertEquals(service.uuid, getServices()[index].uuid)
+ }
+ true
+ }.getOrNull())
+ }
+
+ @Test
+ fun connectFail() = runTest {
+ val device = createDevice("00:11:22:33:44:55")
+ rejectConnect()
+ Assert.assertEquals(true, bluetoothLe.connectGatt(device) { true }.isFailure)
+ }
+
+ private fun acceptConnect() {
+ clientAdapter.onConnectListener =
+ StubClientFrameworkAdapter.OnConnectListener { device, _ ->
+ shadowOf(device).simulateGattConnectionChange(
+ BluetoothGatt.GATT_SUCCESS, BluetoothGatt.STATE_CONNECTED
+ )
+ true
+ }
+
+ clientAdapter.onRequestMtuListener =
+ StubClientFrameworkAdapter.OnRequestMtuListener { mtu ->
+ clientAdapter.callback?.onMtuChanged(clientAdapter.bluetoothGatt, mtu,
+ BluetoothGatt.GATT_SUCCESS)
+ }
+
+ clientAdapter.onDiscoverServicesListener =
+ StubClientFrameworkAdapter.OnDiscoverServicesListener {
+ clientAdapter.gattServices = sampleServices
+ clientAdapter.callback?.onServicesDiscovered(clientAdapter.bluetoothGatt,
+ BluetoothGatt.GATT_SUCCESS)
+ }
+ }
+
+ private fun rejectConnect() {
+ clientAdapter.onConnectListener =
+ StubClientFrameworkAdapter.OnConnectListener { device, _ ->
+ shadowOf(device).simulateGattConnectionChange(
+ BluetoothGatt.GATT_FAILURE, BluetoothGatt.STATE_DISCONNECTED
+ )
+ false
+ }
+ }
+
+ private fun createDevice(address: String): BluetoothDevice {
+ return BluetoothDevice(bluetoothAdapter!!.getRemoteDevice(address))
+ }
+
+ class StubClientFrameworkAdapter(
+ private val baseAdapter: GattClient.FrameworkAdapter
+ ) : GattClient.FrameworkAdapter {
+ var gattServices: List<BluetoothGattService> = listOf()
+ var callback: BluetoothGattCallback? = null
+ override var bluetoothGatt: BluetoothGatt?
+ get() = baseAdapter.bluetoothGatt
+ set(value) { baseAdapter.bluetoothGatt = value }
+ val shadowBluetoothGatt: ShadowBluetoothGatt
+ get() = shadowOf(bluetoothGatt)
+
+ var onConnectListener: OnConnectListener? = null
+ var onRequestMtuListener: OnRequestMtuListener? = null
+ var onDiscoverServicesListener: OnDiscoverServicesListener? = null
+ var onReadCharacteristicListener: OnReadCharacteristicListener? = null
+ var onWriteCharacteristicListener: OnWriteCharacteristicListener? = null
+ var onWriteDescriptorListener: OnWriteDescriptorListener? = null
+ var onSetCharacteristicNotifiationListener: OnSetCharacteristicNotificationListener? = null
+
+ override fun connectGatt(
+ context: Context,
+ device: FwkDevice,
+ callback: BluetoothGattCallback
+ ): Boolean {
+ this.callback = callback
+ baseAdapter.connectGatt(context, device, callback)
+ return onConnectListener?.onConnect(device, callback) ?: false
+ }
+
+ override fun requestMtu(mtu: Int) {
+ baseAdapter.requestMtu(mtu)
+ onRequestMtuListener?.onRequestMtu(mtu)
+ }
+
+ override fun discoverServices() {
+ baseAdapter.discoverServices()
+ onDiscoverServicesListener?.onDiscoverServices()
+ }
+
+ override fun getServices(): List<BluetoothGattService> {
+ return gattServices
+ }
+
+ override fun getService(uuid: UUID): BluetoothGattService? {
+ return gattServices.find { it.uuid == uuid }
+ }
+
+ override fun readCharacteristic(characteristic: BluetoothGattCharacteristic) {
+ baseAdapter.readCharacteristic(characteristic)
+ onReadCharacteristicListener?.onReadCharacteristic(characteristic)
+ }
+
+ override fun writeCharacteristic(
+ characteristic: BluetoothGattCharacteristic,
+ value: ByteArray,
+ writeType: Int
+ ) {
+ baseAdapter.writeCharacteristic(characteristic, value, writeType)
+ onWriteCharacteristicListener?.onWriteCharacteristic(characteristic, value, writeType)
+ }
+
+ override fun writeDescriptor(descriptor: BluetoothGattDescriptor, value: ByteArray) {
+ baseAdapter.writeDescriptor(descriptor, value)
+ onWriteDescriptorListener?.onWriteDescriptor(descriptor, value)
+ }
+
+ override fun setCharacteristicNotification(
+ characteristic: BluetoothGattCharacteristic,
+ enable: Boolean
+ ) {
+ baseAdapter.setCharacteristicNotification(characteristic, enable)
+ onSetCharacteristicNotifiationListener
+ ?.onSetCharacteristicNotification(characteristic, enable)
+ }
+
+ fun interface OnConnectListener {
+ fun onConnect(device: FwkDevice, callback: BluetoothGattCallback): Boolean
+ }
+ fun interface OnRequestMtuListener {
+ fun onRequestMtu(mtu: Int)
+ }
+ fun interface OnDiscoverServicesListener {
+ fun onDiscoverServices()
+ }
+ fun interface OnReadCharacteristicListener {
+ fun onReadCharacteristic(characteristic: BluetoothGattCharacteristic)
+ }
+ fun interface OnWriteCharacteristicListener {
+ fun onWriteCharacteristic(
+ characteristic: BluetoothGattCharacteristic,
+ value: ByteArray,
+ writeType: Int
+ )
+ }
+ fun interface OnWriteDescriptorListener {
+ fun onWriteDescriptor(descriptor: BluetoothGattDescriptor, value: ByteArray)
+ }
+ fun interface OnSetCharacteristicNotificationListener {
+ fun onSetCharacteristicNotification(
+ characteristic: BluetoothGattCharacteristic,
+ enable: Boolean
+ )
+ }
+ }
+}
diff --git a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
index 283bc1d..1dd57c9 100644
--- a/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
+++ b/bluetooth/bluetooth-testing/src/test/kotlin/androidx/bluetooth/testing/RobolectricScanTest.kt
@@ -38,7 +38,7 @@
}
@Test
- fun scanTest() = runTest {
+ fun scan() = runTest {
try {
withTimeout(TIMEOUT_MS) {
bluetoothLe.scan(listOf(ScanFilter())).collect {
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt
index 98eeb61..9e8956d 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/BluetoothDeviceTest.kt
@@ -55,7 +55,7 @@
Assume.assumeNotNull(bluetoothAdapter) // Bluetooth is not available if adapter is null
val fwkBluetoothDevice = bluetoothAdapter!!.getRemoteDevice("00:01:02:03:04:05")
- val bluetoothDevice = BluetoothDevice.of(fwkBluetoothDevice)
+ val bluetoothDevice = BluetoothDevice(fwkBluetoothDevice)
assertEquals(bluetoothDevice.bondState, fwkBluetoothDevice.bondState)
assertEquals(bluetoothDevice.name, fwkBluetoothDevice.name)
diff --git a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
index 9df2442..2e7b1fd 100644
--- a/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
+++ b/bluetooth/bluetooth/src/androidTest/java/androidx/bluetooth/ScanResultTest.kt
@@ -53,8 +53,8 @@
timeStampNanos)
val scanResult = ScanResult(fwkScanResult)
- assertEquals(scanResult.device.name, BluetoothDevice.of(fwkBluetoothDevice).name)
- assertEquals(scanResult.device.bondState, BluetoothDevice.of(fwkBluetoothDevice).bondState)
+ assertEquals(scanResult.device.name, BluetoothDevice(fwkBluetoothDevice).name)
+ assertEquals(scanResult.device.bondState, BluetoothDevice(fwkBluetoothDevice).bondState)
assertEquals(scanResult.deviceAddress.address, address)
assertEquals(scanResult.deviceAddress.addressType,
BluetoothAddress.ADDRESS_TYPE_RANDOM_STATIC)
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt
index 2cc4340..2c34db7 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothDevice.kt
@@ -30,14 +30,9 @@
* @property bondState the bondState for this BluetoothDevice
*
*/
-class BluetoothDevice private constructor(
+class BluetoothDevice @RestrictTo(RestrictTo.Scope.LIBRARY) constructor(
internal val fwkDevice: FwkBluetoothDevice
) {
- internal companion object {
- fun of(device: FwkBluetoothDevice): BluetoothDevice {
- return BluetoothDevice(device)
- }
- }
val id: UUID = UUID.randomUUID()
@get:RequiresPermission(
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
index 24b5d0d..cc95ef8 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/BluetoothLe.kt
@@ -28,6 +28,7 @@
import android.util.Log
import androidx.annotation.RequiresPermission
import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
import java.util.UUID
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.awaitClose
@@ -39,7 +40,7 @@
* operations such as scanning, advertising, and connection with a respective [BluetoothDevice].
*
*/
-class BluetoothLe(private val context: Context) {
+class BluetoothLe constructor(private val context: Context) {
private companion object {
private const val TAG = "BluetoothLe"
@@ -48,6 +49,10 @@
private val bluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?
private val bluetoothAdapter = bluetoothManager?.adapter
+
+ @VisibleForTesting
+ @get:RestrictTo(RestrictTo.Scope.LIBRARY)
+ val client = GattClient(context)
private val server = GattServer(context)
/**
@@ -226,7 +231,7 @@
device: BluetoothDevice,
block: suspend GattClientScope.() -> R
): Result<R> {
- return GattClient().connect(context, device, block)
+ return client.connect(device, block)
}
/**
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
index ab2b0df..411d947 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattClient.kt
@@ -27,6 +27,8 @@
import android.content.Context
import android.os.Build
import androidx.annotation.RequiresPermission
+import androidx.annotation.RestrictTo
+import androidx.annotation.VisibleForTesting
import java.util.UUID
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CompletableDeferred
@@ -48,13 +50,18 @@
/**
* A class for handling operations as a GATT client role.
*/
-internal class GattClient {
- private interface GattClientImpl {
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class GattClient(private val context: Context) {
+ interface FrameworkAdapter {
+ var bluetoothGatt: BluetoothGatt?
fun connectGatt(
context: Context,
device: FwkDevice,
callback: BluetoothGattCallback
): Boolean
+ fun requestMtu(mtu: Int)
+
+ fun discoverServices()
fun getServices(): List<FwkService>
fun getService(uuid: UUID): FwkService?
@@ -70,7 +77,9 @@
fun setCharacteristicNotification(characteristic: FwkCharacteristic, enable: Boolean)
}
- private companion object {
+ @VisibleForTesting
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ companion object {
private const val TAG = "GattClient"
/**
@@ -81,9 +90,11 @@
}
@SuppressLint("ObsoleteSdkInt")
- private val impl: GattClientImpl =
- if (Build.VERSION.SDK_INT >= 33) GattClientImplApi33()
- else BaseGattClientImpl()
+ @VisibleForTesting
+ @RestrictTo(RestrictTo.Scope.LIBRARY)
+ var fwkAdapter: FrameworkAdapter =
+ if (Build.VERSION.SDK_INT >= 33) FrameworkAdapterApi33()
+ else FrameworkAdapterBase()
private sealed interface CallbackResult {
class OnCharacteristicRead(
@@ -116,7 +127,6 @@
@SuppressLint("MissingPermission")
suspend fun <R> connect(
- context: Context,
device: BluetoothDevice,
block: suspend BluetoothLe.GattClientScope.() -> R
): Result<R> = coroutineScope {
@@ -130,7 +140,7 @@
val callback = object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
if (newState == BluetoothGatt.STATE_CONNECTED) {
- gatt?.requestMtu(GATT_MAX_MTU)
+ fwkAdapter.requestMtu(GATT_MAX_MTU)
} else {
connectResult.cancel("connect failed")
}
@@ -138,16 +148,14 @@
override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
if (status == BluetoothGatt.GATT_SUCCESS) {
- gatt?.discoverServices()
+ fwkAdapter.discoverServices()
} else {
connectResult.cancel("mtu request failed")
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
- gatt?.let {
- attributeMap.updateWithFrameworkServices(it.services)
- }
+ attributeMap.updateWithFrameworkServices(fwkAdapter.getServices())
if (status == BluetoothGatt.GATT_SUCCESS) connectResult.complete(Unit)
else connectResult.cancel("service discover failed")
}
@@ -208,7 +216,7 @@
}
}
}
- if (!impl.connectGatt(context, device.fwkDevice, callback)) {
+ if (!fwkAdapter.connectGatt(context, device.fwkDevice, callback)) {
return@coroutineScope Result.failure(CancellationException("failed to connect"))
}
@@ -230,7 +238,7 @@
}
override fun getService(uuid: UUID): GattService? {
- return impl.getService(uuid)?.let { attributeMap.fromFwkService(it) }
+ return fwkAdapter.getService(uuid)?.let { attributeMap.fromFwkService(it) }
}
override suspend fun readCharacteristic(characteristic: GattCharacteristic):
@@ -239,7 +247,7 @@
return Result.failure(IllegalArgumentException("can't read the characteristic"))
}
return runTask {
- impl.readCharacteristic(characteristic.fwkCharacteristic)
+ fwkAdapter.readCharacteristic(characteristic.fwkCharacteristic)
val res = takeMatchingResult<CallbackResult.OnCharacteristicRead>(
callbackResultsFlow
) {
@@ -263,7 +271,8 @@
)
}
return runTask {
- impl.writeCharacteristic(characteristic.fwkCharacteristic, value, writeType)
+ fwkAdapter.writeCharacteristic(
+ characteristic.fwkCharacteristic, value, writeType)
val res = takeMatchingResult<CallbackResult.OnCharacteristicWrite>(
callbackResultsFlow
) {
@@ -298,11 +307,11 @@
}
runTask {
- impl.setCharacteristicNotification(
+ fwkAdapter.setCharacteristicNotification(
characteristic.fwkCharacteristic, /*enable=*/true
)
- impl.writeDescriptor(cccd, FwkDescriptor.ENABLE_NOTIFICATION_VALUE)
+ fwkAdapter.writeDescriptor(cccd, FwkDescriptor.ENABLE_NOTIFICATION_VALUE)
val res = takeMatchingResult<CallbackResult.OnDescriptorWrite>(
callbackResultsFlow
) {
@@ -317,11 +326,11 @@
launch {
unregisterSubscribeListener(characteristic.fwkCharacteristic)
}
- impl.setCharacteristicNotification(
+ fwkAdapter.setCharacteristicNotification(
characteristic.fwkCharacteristic, /*enable=*/false
)
- impl.writeDescriptor(cccd, FwkDescriptor.DISABLE_NOTIFICATION_VALUE)
+ fwkAdapter.writeDescriptor(cccd, FwkDescriptor.DISABLE_NOTIFICATION_VALUE)
}
}
}
@@ -374,8 +383,8 @@
return flow.filter { it is R && predicate(it) }.first() as R
}
- private open class BaseGattClientImpl : GattClientImpl {
- var bluetoothGatt: BluetoothGatt? = null
+ private open class FrameworkAdapterBase : FrameworkAdapter {
+ override var bluetoothGatt: BluetoothGatt? = null
@RequiresPermission(BLUETOOTH_CONNECT)
override fun connectGatt(
@@ -387,6 +396,16 @@
return bluetoothGatt != null
}
+ @RequiresPermission(BLUETOOTH_CONNECT)
+ override fun requestMtu(mtu: Int) {
+ bluetoothGatt?.requestMtu(mtu)
+ }
+
+ @RequiresPermission(BLUETOOTH_CONNECT)
+ override fun discoverServices() {
+ bluetoothGatt?.discoverServices()
+ }
+
override fun getServices(): List<FwkService> {
return bluetoothGatt?.services ?: listOf()
}
@@ -427,7 +446,7 @@
}
}
- private open class GattClientImplApi33 : BaseGattClientImpl() {
+ private open class FrameworkAdapterApi33 : FrameworkAdapterBase() {
@RequiresPermission(BLUETOOTH_CONNECT)
override fun writeCharacteristic(
characteristic: FwkCharacteristic,
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
index 0c22a3b..785983d 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/GattServer.kt
@@ -99,7 +99,7 @@
BluetoothProfile.STATE_CONNECTED -> {
trySend(
BluetoothLe.GattServerConnectionRequest(
- BluetoothDevice.of(device),
+ BluetoothDevice(device),
this@GattServer,
addSession(device)
)
diff --git a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
index f98714b..045b3de 100644
--- a/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
+++ b/bluetooth/bluetooth/src/main/java/androidx/bluetooth/ScanResult.kt
@@ -39,7 +39,7 @@
/** Remote Bluetooth device found. */
val device: BluetoothDevice
- get() = BluetoothDevice.of(fwkScanResult.device)
+ get() = BluetoothDevice(fwkScanResult.device)
// TODO(kihongs) Find a way to get address type from framework scan result
/** Bluetooth address for the remote device found. */
diff --git a/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt b/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
index e4d7736..8d92531 100644
--- a/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
+++ b/buildSrc-tests/src/test/java/androidx/build/testConfiguration/AndroidTestConfigBuilderTest.kt
@@ -350,6 +350,7 @@
<option name="wifi:disable" value="true" />
<option name="instrumentation-arg" key="notAnnotation" value="androidx.test.filters.FlakyTest" />
<option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener" />
+ <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.SideEffectRunListener" />
<include name="google/unbundled/common/setup" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
@@ -358,6 +359,7 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="cmd package compile -f -m speed com.androidx.placeholder.Placeholder" />
+ <option name="run-command-timeout" value="240000" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="runner" value="com.example.Runner"/>
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
index 1d045d0..8cb0a3d 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXComposeImplPlugin.kt
@@ -84,10 +84,6 @@
val isPublished = androidXExtension.shouldPublish()
it.lint {
- // Too many Kotlin features require synthetic accessors - we want to rely on R8
- // to
- // remove these accessors
- disable.add("SyntheticAccessor")
// These lint checks are normally a warning (or lower), but we ignore (in
// AndroidX)
// warnings in Lint, so we make it an error here so it will fail the build.
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index 7cc787b..21fb3f1 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -61,6 +61,9 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
+import org.gradle.api.artifacts.CacheableRule
+import org.gradle.api.artifacts.ComponentMetadataContext
+import org.gradle.api.artifacts.ComponentMetadataRule
import org.gradle.api.artifacts.Configuration
import org.gradle.api.component.SoftwareComponentFactory
import org.gradle.api.file.DuplicatesStrategy
@@ -82,6 +85,7 @@
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.findByType
import org.gradle.kotlin.dsl.getByType
+import org.gradle.kotlin.dsl.withModule
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
@@ -297,20 +301,16 @@
private fun Project.configureKotlinVersion() {
val kotlinVersionStringProvider = androidXConfiguration.kotlinBomVersion
- // Resolve Kotlin versions to the target version or higher.
+ // Resolve unspecified Kotlin versions to the target version.
configurations.all { configuration ->
configuration.resolutionStrategy { strategy ->
strategy.eachDependency { details ->
if (details.requested.group == "org.jetbrains.kotlin") {
- val requestedVersion =
- if (details.requested.version.isNullOrEmpty()) {
- null
- } else {
- Version(details.requested.version!!)
- }
- val bomVersion = kotlinVersionStringProvider.get()
- if (requestedVersion == null || requestedVersion < Version(bomVersion)) {
- details.useVersion(bomVersion)
+ if (
+ details.requested.group == "org.jetbrains.kotlin" &&
+ details.requested.version == null
+ ) {
+ details.useVersion(kotlinVersionStringProvider.get())
}
}
}
@@ -335,6 +335,35 @@
kotlinExtension.coreLibrariesVersion = kotlinVersionStringProvider.get()
}
}
+
+ // Resolve classpath conflicts caused by kotlin-stdlib-jdk7 and -jdk8 artifacts by amending
+ // the kotlin-stdlib artifact metadata to add same-version constraints.
+ project.dependencies {
+ components { componentMetadata ->
+ componentMetadata.withModule<KotlinStdlibDependenciesRule>(
+ "org.jetbrains.kotlin:kotlin-stdlib"
+ )
+ }
+ }
+ }
+
+ @CacheableRule
+ internal abstract class KotlinStdlibDependenciesRule : ComponentMetadataRule {
+ override fun execute(context: ComponentMetadataContext) {
+ val module = context.details.id
+ val version = module.version
+ context.details.allVariants { variantMetadata ->
+ variantMetadata.withDependencyConstraints { constraintsMetadata ->
+ val reason = "${module.name} is in atomic group ${module.group}"
+ constraintsMetadata.add("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$version") {
+ it.because(reason)
+ }
+ constraintsMetadata.add("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version") {
+ it.because(reason)
+ }
+ }
+ }
+ }
}
private fun configureWithKotlinPlugin(
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt b/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
index 2552af0..28200ee 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/LintConfiguration.kt
@@ -397,15 +397,9 @@
fatal.add("LambdaLast")
fatal.add("UnknownNullness")
- // Only override if not set explicitly.
- // Some Kotlin projects may wish to disable this.
- if (
- isLibrary &&
- !disable.contains("SyntheticAccessor") &&
- extension.type != LibraryType.SAMPLES
- ) {
- fatal.add("SyntheticAccessor")
- }
+ // Too many Kotlin features require synthetic accessors - we want to rely on R8 to
+ // remove these accessors
+ disable.add("SyntheticAccessor")
// Only check for missing translations in finalized (beta and later) modules.
if (extension.mavenVersion?.isFinalApi() == true) {
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
index 657f702..90fd4df 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/testConfiguration/AndroidTestConfigBuilder.kt
@@ -242,6 +242,7 @@
"""
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="${benchmarkPostInstallCommand(packageName)}" />
+ <option name="run-command-timeout" value="240000" />
</target_preparer>
""".trimIndent()
@@ -323,6 +324,7 @@
private val MICROBENCHMARK_POSTSUBMIT_OPTIONS =
"""
<option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.InstrumentationResultsRunListener" />
+ <option name="instrumentation-arg" key="listener" value="androidx.benchmark.junit4.SideEffectRunListener" />
"""
.trimIndent()
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
index 4ba4278..dd11df8 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/Requests.kt
@@ -141,17 +141,6 @@
) {
}
- @Deprecated(
- message = "Migrating to using RequestFailure instead of CaptureFailure",
- level = DeprecationLevel.WARNING
- )
- fun onFailed(
- requestMetadata: RequestMetadata,
- frameNumber: FrameNumber,
- captureFailure: CaptureFailure
- ) {
- }
-
/**
* onFailed occurs when a CaptureRequest failed in some way and the frame will not receive
* the [onTotalCaptureResult] callback.
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExtensionSessionWrapper.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExtensionSessionWrapper.kt
index 1e04f26..4456fbb 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExtensionSessionWrapper.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ExtensionSessionWrapper.kt
@@ -296,7 +296,6 @@
request: CaptureRequest,
result: TotalCaptureResult
) {
- Log.info { "Extension session listener's onComplete requires Android T or higher." }
val frameNumber = frameQueue.remove()
captureCallback.onCaptureCompleted(request, result, FrameNumber(frameNumber))
}
diff --git a/camera/camera-camera2/api/1.3.0-beta03.txt b/camera/camera-camera2/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..87c79d0
--- /dev/null
+++ b/camera/camera-camera2/api/1.3.0-beta03.txt
@@ -0,0 +1,54 @@
+// Signature format: 4.0
+package androidx.camera.camera2 {
+
+ @RequiresApi(21) public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
+package androidx.camera.camera2.interop {
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> addCaptureRequestOptions(androidx.camera.camera2.interop.CaptureRequestOptions);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> clearCaptureRequestOptions();
+ method public static androidx.camera.camera2.interop.Camera2CameraControl from(androidx.camera.core.CameraControl);
+ method public androidx.camera.camera2.interop.CaptureRequestOptions getCaptureRequestOptions();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setCaptureRequestOptions(androidx.camera.camera2.interop.CaptureRequestOptions);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraInfo {
+ method public static androidx.camera.camera2.interop.Camera2CameraInfo from(androidx.camera.core.CameraInfo);
+ method public <T> T? getCameraCharacteristic(android.hardware.camera2.CameraCharacteristics.Key<T!>);
+ method public String getCameraId();
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2Interop {
+ }
+
+ @RequiresApi(21) public static final class Camera2Interop.Extender<T> {
+ ctor public Camera2Interop.Extender(androidx.camera.core.ExtendableBuilder<T!>);
+ method public <ValueT> androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setDeviceStateCallback(android.hardware.camera2.CameraDevice.StateCallback);
+ method @RequiresApi(28) public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setPhysicalCameraId(String);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionCaptureCallback(android.hardware.camera2.CameraCaptureSession.CaptureCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionStateCallback(android.hardware.camera2.CameraCaptureSession.StateCallback);
+ method @RequiresApi(33) public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setStreamUseCase(long);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public class CaptureRequestOptions {
+ method public <ValueT> ValueT? getCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>);
+ }
+
+ @RequiresApi(21) public static final class CaptureRequestOptions.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.camera2.interop.CaptureRequestOptions> {
+ ctor public CaptureRequestOptions.Builder();
+ method public androidx.camera.camera2.interop.CaptureRequestOptions build();
+ method public <ValueT> androidx.camera.camera2.interop.CaptureRequestOptions.Builder clearCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>);
+ method public <ValueT> androidx.camera.camera2.interop.CaptureRequestOptions.Builder setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCamera2Interop {
+ }
+
+}
+
diff --git a/camera/camera-camera2/api/res-1.3.0-beta03.txt b/camera/camera-camera2/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-camera2/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-camera2/api/restricted_1.3.0-beta03.txt b/camera/camera-camera2/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..87c79d0
--- /dev/null
+++ b/camera/camera-camera2/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,54 @@
+// Signature format: 4.0
+package androidx.camera.camera2 {
+
+ @RequiresApi(21) public final class Camera2Config {
+ method public static androidx.camera.core.CameraXConfig defaultConfig();
+ }
+
+}
+
+package androidx.camera.camera2.interop {
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> addCaptureRequestOptions(androidx.camera.camera2.interop.CaptureRequestOptions);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> clearCaptureRequestOptions();
+ method public static androidx.camera.camera2.interop.Camera2CameraControl from(androidx.camera.core.CameraControl);
+ method public androidx.camera.camera2.interop.CaptureRequestOptions getCaptureRequestOptions();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setCaptureRequestOptions(androidx.camera.camera2.interop.CaptureRequestOptions);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraInfo {
+ method public static androidx.camera.camera2.interop.Camera2CameraInfo from(androidx.camera.core.CameraInfo);
+ method public <T> T? getCameraCharacteristic(android.hardware.camera2.CameraCharacteristics.Key<T!>);
+ method public String getCameraId();
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2Interop {
+ }
+
+ @RequiresApi(21) public static final class Camera2Interop.Extender<T> {
+ ctor public Camera2Interop.Extender(androidx.camera.core.ExtendableBuilder<T!>);
+ method public <ValueT> androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setDeviceStateCallback(android.hardware.camera2.CameraDevice.StateCallback);
+ method @RequiresApi(28) public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setPhysicalCameraId(String);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionCaptureCallback(android.hardware.camera2.CameraCaptureSession.CaptureCallback);
+ method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionStateCallback(android.hardware.camera2.CameraCaptureSession.StateCallback);
+ method @RequiresApi(33) public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setStreamUseCase(long);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @androidx.camera.camera2.interop.ExperimentalCamera2Interop public class CaptureRequestOptions {
+ method public <ValueT> ValueT? getCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>);
+ }
+
+ @RequiresApi(21) public static final class CaptureRequestOptions.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.camera2.interop.CaptureRequestOptions> {
+ ctor public CaptureRequestOptions.Builder();
+ method public androidx.camera.camera2.interop.CaptureRequestOptions build();
+ method public <ValueT> androidx.camera.camera2.interop.CaptureRequestOptions.Builder clearCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>);
+ method public <ValueT> androidx.camera.camera2.interop.CaptureRequestOptions.Builder setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCamera2Interop {
+ }
+
+}
+
diff --git a/camera/camera-core/api/1.3.0-beta03.txt b/camera/camera-core/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..adace2b
--- /dev/null
+++ b/camera/camera-core/api/1.3.0-beta03.txt
@@ -0,0 +1,612 @@
+// Signature format: 4.0
+package androidx.camera.core {
+
+ @RequiresApi(21) public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ field public static final int RATIO_DEFAULT = -1; // 0xffffffff
+ }
+
+ @RequiresApi(21) public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ @RequiresApi(21) public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> setExposureCompensationIndex(int);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ @RequiresApi(21) public abstract class CameraEffect {
+ ctor protected CameraEffect(int, java.util.concurrent.Executor, androidx.camera.core.ImageProcessor, androidx.core.util.Consumer<java.lang.Throwable!>);
+ ctor protected CameraEffect(int, java.util.concurrent.Executor, androidx.camera.core.SurfaceProcessor, androidx.core.util.Consumer<java.lang.Throwable!>);
+ method public androidx.core.util.Consumer<java.lang.Throwable!> getErrorListener();
+ method public java.util.concurrent.Executor getExecutor();
+ method public androidx.camera.core.SurfaceProcessor? getSurfaceProcessor();
+ method public int getTargets();
+ field public static final int IMAGE_CAPTURE = 4; // 0x4
+ field public static final int PREVIEW = 1; // 0x1
+ field public static final int VIDEO_CAPTURE = 2; // 0x2
+ }
+
+ @RequiresApi(21) public interface CameraFilter {
+ method public java.util.List<androidx.camera.core.CameraInfo!> filter(java.util.List<androidx.camera.core.CameraInfo!>);
+ }
+
+ @RequiresApi(21) public interface CameraInfo {
+ method public androidx.camera.core.CameraSelector getCameraSelector();
+ method public androidx.lifecycle.LiveData<androidx.camera.core.CameraState!> getCameraState();
+ method public androidx.camera.core.ExposureState getExposureState();
+ method @FloatRange(from=0, fromInclusive=false) public default float getIntrinsicZoomRatio();
+ method public default int getLensFacing();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public default java.util.Set<android.util.Range<java.lang.Integer!>!> getSupportedFrameRateRanges();
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+ method public boolean hasFlashUnit();
+ method public default boolean isFocusMeteringSupported(androidx.camera.core.FocusMeteringAction);
+ method @SuppressCompatibility @androidx.camera.core.ExperimentalZeroShutterLag public default boolean isZslSupported();
+ }
+
+ @RequiresApi(21) public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ @RequiresApi(21) public interface CameraProvider {
+ method public java.util.List<androidx.camera.core.CameraInfo!> getAvailableCameraInfos();
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ }
+
+ @RequiresApi(21) public final class CameraSelector {
+ method public java.util.List<androidx.camera.core.CameraInfo!> filter(java.util.List<androidx.camera.core.CameraInfo!>);
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field @SuppressCompatibility @androidx.camera.core.ExperimentalLensFacing public static final int LENS_FACING_EXTERNAL = 2; // 0x2
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ field public static final int LENS_FACING_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector.Builder addCameraFilter(androidx.camera.core.CameraFilter);
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class CameraState {
+ ctor public CameraState();
+ method public static androidx.camera.core.CameraState create(androidx.camera.core.CameraState.Type);
+ method public static androidx.camera.core.CameraState create(androidx.camera.core.CameraState.Type, androidx.camera.core.CameraState.StateError?);
+ method public abstract androidx.camera.core.CameraState.StateError? getError();
+ method public abstract androidx.camera.core.CameraState.Type getType();
+ field public static final int ERROR_CAMERA_DISABLED = 5; // 0x5
+ field public static final int ERROR_CAMERA_FATAL_ERROR = 6; // 0x6
+ field public static final int ERROR_CAMERA_IN_USE = 2; // 0x2
+ field public static final int ERROR_DO_NOT_DISTURB_MODE_ENABLED = 7; // 0x7
+ field public static final int ERROR_MAX_CAMERAS_IN_USE = 1; // 0x1
+ field public static final int ERROR_OTHER_RECOVERABLE_ERROR = 3; // 0x3
+ field public static final int ERROR_STREAM_CONFIG = 4; // 0x4
+ }
+
+ public enum CameraState.ErrorType {
+ enum_constant public static final androidx.camera.core.CameraState.ErrorType CRITICAL;
+ enum_constant public static final androidx.camera.core.CameraState.ErrorType RECOVERABLE;
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class CameraState.StateError {
+ ctor public CameraState.StateError();
+ method public static androidx.camera.core.CameraState.StateError create(int);
+ method public static androidx.camera.core.CameraState.StateError create(int, Throwable?);
+ method public abstract Throwable? getCause();
+ method public abstract int getCode();
+ method public androidx.camera.core.CameraState.ErrorType getType();
+ }
+
+ public enum CameraState.Type {
+ enum_constant public static final androidx.camera.core.CameraState.Type CLOSED;
+ enum_constant public static final androidx.camera.core.CameraState.Type CLOSING;
+ enum_constant public static final androidx.camera.core.CameraState.Type OPEN;
+ enum_constant public static final androidx.camera.core.CameraState.Type OPENING;
+ enum_constant public static final androidx.camera.core.CameraState.Type PENDING_OPEN;
+ }
+
+ @RequiresApi(21) public class CameraUnavailableException extends java.lang.Exception {
+ ctor public CameraUnavailableException(int);
+ ctor public CameraUnavailableException(int, String?);
+ ctor public CameraUnavailableException(int, String?, Throwable?);
+ ctor public CameraUnavailableException(int, Throwable?);
+ method public int getReason();
+ field public static final int CAMERA_DISABLED = 1; // 0x1
+ field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+ field public static final int CAMERA_ERROR = 3; // 0x3
+ field public static final int CAMERA_IN_USE = 4; // 0x4
+ field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+ field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+ field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ @RequiresApi(21) public final class CameraXConfig {
+ method public androidx.camera.core.CameraSelector? getAvailableCamerasLimiter(androidx.camera.core.CameraSelector?);
+ method public java.util.concurrent.Executor? getCameraExecutor(java.util.concurrent.Executor?);
+ method public int getMinimumLoggingLevel();
+ method public android.os.Handler? getSchedulerHandler(android.os.Handler?);
+ }
+
+ public static final class CameraXConfig.Builder {
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setAvailableCamerasLimiter(androidx.camera.core.CameraSelector);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.CameraXConfig.Builder setMinimumLoggingLevel(@IntRange(from=android.util.Log.DEBUG, to=android.util.Log.ERROR) int);
+ method public androidx.camera.core.CameraXConfig.Builder setSchedulerHandler(android.os.Handler);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ @RequiresApi(21) public class ConcurrentCamera {
+ ctor public ConcurrentCamera(java.util.List<androidx.camera.core.Camera!>);
+ method public java.util.List<androidx.camera.core.Camera!> getCameras();
+ }
+
+ public static final class ConcurrentCamera.SingleCameraConfig {
+ ctor public ConcurrentCamera.SingleCameraConfig(androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup, androidx.lifecycle.LifecycleOwner);
+ method public androidx.camera.core.CameraSelector getCameraSelector();
+ method public androidx.lifecycle.LifecycleOwner getLifecycleOwner();
+ method public androidx.camera.core.UseCaseGroup getUseCaseGroup();
+ }
+
+ @RequiresApi(21) public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+ }
+
+ @RequiresApi(21) public final class DynamicRange {
+ ctor public DynamicRange(int, int);
+ method public int getBitDepth();
+ method public int getEncoding();
+ field public static final int BIT_DEPTH_10_BIT = 10; // 0xa
+ field public static final int BIT_DEPTH_8_BIT = 8; // 0x8
+ field public static final int BIT_DEPTH_UNSPECIFIED = 0; // 0x0
+ field public static final androidx.camera.core.DynamicRange DOLBY_VISION_10_BIT;
+ field public static final androidx.camera.core.DynamicRange DOLBY_VISION_8_BIT;
+ field public static final int ENCODING_DOLBY_VISION = 6; // 0x6
+ field public static final int ENCODING_HDR10 = 4; // 0x4
+ field public static final int ENCODING_HDR10_PLUS = 5; // 0x5
+ field public static final int ENCODING_HDR_UNSPECIFIED = 2; // 0x2
+ field public static final int ENCODING_HLG = 3; // 0x3
+ field public static final int ENCODING_SDR = 1; // 0x1
+ field public static final int ENCODING_UNSPECIFIED = 0; // 0x0
+ field public static final androidx.camera.core.DynamicRange HDR10_10_BIT;
+ field public static final androidx.camera.core.DynamicRange HDR10_PLUS_10_BIT;
+ field public static final androidx.camera.core.DynamicRange HDR_UNSPECIFIED_10_BIT;
+ field public static final androidx.camera.core.DynamicRange HLG_10_BIT;
+ field public static final androidx.camera.core.DynamicRange SDR;
+ field public static final androidx.camera.core.DynamicRange UNSPECIFIED;
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalLensFacing {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalUseCaseApi {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalZeroShutterLag {
+ }
+
+ @RequiresApi(21) public interface ExposureState {
+ method public int getExposureCompensationIndex();
+ method public android.util.Range<java.lang.Integer!> getExposureCompensationRange();
+ method public android.util.Rational getExposureCompensationStep();
+ method public boolean isExposureCompensationSupported();
+ }
+
+ @RequiresApi(21) public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ @RequiresApi(21) public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ @RequiresApi(21) public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ @RequiresApi(21) public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method @SuppressCompatibility @androidx.camera.core.ExperimentalUseCaseApi public java.util.concurrent.Executor? getBackgroundExecutor();
+ method public int getBackpressureStrategy();
+ method public int getImageQueueDepth();
+ method public int getOutputImageFormat();
+ method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
+ method public int getTargetRotation();
+ method public boolean isOutputImageRotationEnabled();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int COORDINATE_SYSTEM_ORIGINAL = 0; // 0x0
+ field public static final int OUTPUT_IMAGE_FORMAT_RGBA_8888 = 2; // 0x2
+ field public static final int OUTPUT_IMAGE_FORMAT_YUV_420_888 = 1; // 0x1
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ method public default android.util.Size? getDefaultTargetResolution();
+ method public default int getTargetCoordinateSystem();
+ method public default void updateTransform(android.graphics.Matrix?);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setOutputImageFormat(int);
+ method @RequiresApi(23) public androidx.camera.core.ImageAnalysis.Builder setOutputImageRotationEnabled(boolean);
+ method public androidx.camera.core.ImageAnalysis.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+ method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ @RequiresApi(21) public final class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getCaptureMode();
+ method public int getFlashMode();
+ method @IntRange(from=1, to=100) public int getJpegQuality();
+ method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
+ method public int getTargetRotation();
+ method public void setCropAspectRatio(android.util.Rational);
+ method public void setFlashMode(int);
+ method public void setTargetRotation(int);
+ method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field @SuppressCompatibility @androidx.camera.core.ExperimentalZeroShutterLag public static final int CAPTURE_MODE_ZERO_SHUTTER_LAG = 2; // 0x2
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setJpegQuality(@IntRange(from=1, to=100) int);
+ method public androidx.camera.core.ImageCapture.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+ method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+ }
+
+ public static final class ImageCapture.OutputFileOptions {
+ }
+
+ public static final class ImageCapture.OutputFileOptions.Builder {
+ ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+ method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+ method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+ }
+
+ public static class ImageCapture.OutputFileResults {
+ method public android.net.Uri? getSavedUri();
+ }
+
+ @RequiresApi(21) public class ImageCaptureException extends java.lang.Exception {
+ ctor public ImageCaptureException(int, String, Throwable?);
+ method public int getImageCaptureError();
+ }
+
+ @RequiresApi(21) public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public default android.graphics.Matrix getSensorToBufferTransformMatrix();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProcessor {
+ method public androidx.camera.core.ImageProcessor.Response process(androidx.camera.core.ImageProcessor.Request) throws androidx.camera.core.ProcessingException;
+ }
+
+ public static interface ImageProcessor.Request {
+ method public androidx.camera.core.ImageProxy getInputImage();
+ method public int getOutputFormat();
+ }
+
+ public static interface ImageProcessor.Response {
+ method public androidx.camera.core.ImageProxy getOutputImage();
+ }
+
+ @RequiresApi(21) public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method @SuppressCompatibility @androidx.camera.core.ExperimentalGetImage public android.media.Image? getImage();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ method public default android.graphics.Bitmap toBitmap();
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ @RequiresApi(21) public class InitializationException extends java.lang.Exception {
+ ctor public InitializationException(String?);
+ ctor public InitializationException(String?, Throwable?);
+ ctor public InitializationException(Throwable?);
+ }
+
+ @RequiresApi(21) public class MeteringPoint {
+ method public float getSize();
+ }
+
+ @RequiresApi(21) public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ @RequiresApi(21) public class MirrorMode {
+ field public static final int MIRROR_MODE_OFF = 0; // 0x0
+ field public static final int MIRROR_MODE_ON = 1; // 0x1
+ field public static final int MIRROR_MODE_ON_FRONT_ONLY = 2; // 0x2
+ }
+
+ @RequiresApi(21) public final class Preview extends androidx.camera.core.UseCase {
+ method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
+ method public android.util.Range<java.lang.Integer!> getTargetFrameRate();
+ method public int getTargetRotation();
+ method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+ method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+ method public void setTargetRotation(int);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+ method @Deprecated public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetFrameRate(android.util.Range<java.lang.Integer!>);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method @Deprecated public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.SurfaceProvider {
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ }
+
+ public class ProcessingException extends java.lang.Exception {
+ ctor public ProcessingException();
+ }
+
+ @RequiresApi(21) public class ResolutionInfo {
+ ctor public ResolutionInfo(android.util.Size, android.graphics.Rect, int);
+ method public android.graphics.Rect getCropRect();
+ method public android.util.Size getResolution();
+ method public int getRotationDegrees();
+ }
+
+ @RequiresApi(21) public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public interface SurfaceOutput extends java.io.Closeable {
+ method public void close();
+ method public android.util.Size getSize();
+ method public android.view.Surface getSurface(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceOutput.Event!>);
+ method public int getTargets();
+ method public void updateTransformMatrix(float[], float[]);
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceOutput.Event {
+ method public abstract int getEventCode();
+ method public abstract androidx.camera.core.SurfaceOutput getSurfaceOutput();
+ field public static final int EVENT_REQUEST_CLOSE = 0; // 0x0
+ }
+
+ public interface SurfaceProcessor {
+ method public void onInputSurface(androidx.camera.core.SurfaceRequest) throws androidx.camera.core.ProcessingException;
+ method public void onOutputSurface(androidx.camera.core.SurfaceOutput) throws androidx.camera.core.ProcessingException;
+ }
+
+ @RequiresApi(21) public final class SurfaceRequest {
+ method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+ method public void clearTransformationInfoListener();
+ method public androidx.camera.core.DynamicRange getDynamicRange();
+ method public android.util.Size getResolution();
+ method public boolean invalidate();
+ method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+ method public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
+ method public boolean willNotProvideSurface();
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+ method public abstract int getResultCode();
+ method public abstract android.view.Surface getSurface();
+ field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+ field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+ field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+ field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+ field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
+ method public abstract android.graphics.Rect getCropRect();
+ method public abstract int getRotationDegrees();
+ }
+
+ public static interface SurfaceRequest.TransformationInfoListener {
+ method public void onTransformationInfoUpdate(androidx.camera.core.SurfaceRequest.TransformationInfo);
+ }
+
+ @RequiresApi(21) public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ @RequiresApi(21) public abstract class UseCase {
+ method public static int snapToSurfaceRotation(@IntRange(from=0, to=359) int);
+ }
+
+ @RequiresApi(21) public final class UseCaseGroup {
+ method public java.util.List<androidx.camera.core.CameraEffect!> getEffects();
+ method public java.util.List<androidx.camera.core.UseCase!> getUseCases();
+ method public androidx.camera.core.ViewPort? getViewPort();
+ }
+
+ public static final class UseCaseGroup.Builder {
+ ctor public UseCaseGroup.Builder();
+ method public androidx.camera.core.UseCaseGroup.Builder addEffect(androidx.camera.core.CameraEffect);
+ method public androidx.camera.core.UseCaseGroup.Builder addUseCase(androidx.camera.core.UseCase);
+ method public androidx.camera.core.UseCaseGroup build();
+ method public androidx.camera.core.UseCaseGroup.Builder setViewPort(androidx.camera.core.ViewPort);
+ }
+
+ @RequiresApi(21) public final class ViewPort {
+ method public android.util.Rational getAspectRatio();
+ method public int getLayoutDirection();
+ method public int getRotation();
+ method public int getScaleType();
+ field public static final int FILL_CENTER = 1; // 0x1
+ field public static final int FILL_END = 2; // 0x2
+ field public static final int FILL_START = 0; // 0x0
+ field public static final int FIT = 3; // 0x3
+ }
+
+ public static final class ViewPort.Builder {
+ ctor public ViewPort.Builder(android.util.Rational, int);
+ method public androidx.camera.core.ViewPort build();
+ method public androidx.camera.core.ViewPort.Builder setLayoutDirection(int);
+ method public androidx.camera.core.ViewPort.Builder setScaleType(int);
+ }
+
+ @RequiresApi(21) public interface ZoomState {
+ method public float getLinearZoom();
+ method public float getMaxZoomRatio();
+ method public float getMinZoomRatio();
+ method public float getZoomRatio();
+ }
+
+}
+
+package androidx.camera.core.resolutionselector {
+
+ @RequiresApi(21) public final class AspectRatioStrategy {
+ ctor public AspectRatioStrategy(int, int);
+ method public int getFallbackRule();
+ method public int getPreferredAspectRatio();
+ field public static final int FALLBACK_RULE_AUTO = 1; // 0x1
+ field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+ field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_16_9_FALLBACK_AUTO_STRATEGY;
+ field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_4_3_FALLBACK_AUTO_STRATEGY;
+ }
+
+ @RequiresApi(21) public interface ResolutionFilter {
+ method public java.util.List<android.util.Size!> filter(java.util.List<android.util.Size!>, int);
+ }
+
+ @RequiresApi(21) public final class ResolutionSelector {
+ method public int getAllowedResolutionMode();
+ method public androidx.camera.core.resolutionselector.AspectRatioStrategy getAspectRatioStrategy();
+ method public androidx.camera.core.resolutionselector.ResolutionFilter? getResolutionFilter();
+ method public androidx.camera.core.resolutionselector.ResolutionStrategy? getResolutionStrategy();
+ field public static final int PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION = 0; // 0x0
+ field public static final int PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE = 1; // 0x1
+ }
+
+ public static final class ResolutionSelector.Builder {
+ ctor public ResolutionSelector.Builder();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector build();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setAllowedResolutionMode(int);
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setAspectRatioStrategy(androidx.camera.core.resolutionselector.AspectRatioStrategy);
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionFilter(androidx.camera.core.resolutionselector.ResolutionFilter);
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionStrategy(androidx.camera.core.resolutionselector.ResolutionStrategy);
+ }
+
+ @RequiresApi(21) public final class ResolutionStrategy {
+ ctor public ResolutionStrategy(android.util.Size, int);
+ method public android.util.Size? getBoundSize();
+ method public int getFallbackRule();
+ field public static final int FALLBACK_RULE_CLOSEST_HIGHER = 2; // 0x2
+ field public static final int FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER = 1; // 0x1
+ field public static final int FALLBACK_RULE_CLOSEST_LOWER = 4; // 0x4
+ field public static final int FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER = 3; // 0x3
+ field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+ field public static final androidx.camera.core.resolutionselector.ResolutionStrategy HIGHEST_AVAILABLE_STRATEGY;
+ }
+
+}
+
diff --git a/camera/camera-core/api/res-1.3.0-beta03.txt b/camera/camera-core/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-core/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-core/api/restricted_1.3.0-beta03.txt b/camera/camera-core/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..adace2b
--- /dev/null
+++ b/camera/camera-core/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,612 @@
+// Signature format: 4.0
+package androidx.camera.core {
+
+ @RequiresApi(21) public class AspectRatio {
+ field public static final int RATIO_16_9 = 1; // 0x1
+ field public static final int RATIO_4_3 = 0; // 0x0
+ field public static final int RATIO_DEFAULT = -1; // 0xffffffff
+ }
+
+ @RequiresApi(21) public interface Camera {
+ method public androidx.camera.core.CameraControl getCameraControl();
+ method public androidx.camera.core.CameraInfo getCameraInfo();
+ }
+
+ @RequiresApi(21) public interface CameraControl {
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> setExposureCompensationIndex(int);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+ }
+
+ public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+ }
+
+ @RequiresApi(21) public abstract class CameraEffect {
+ ctor protected CameraEffect(int, java.util.concurrent.Executor, androidx.camera.core.ImageProcessor, androidx.core.util.Consumer<java.lang.Throwable!>);
+ ctor protected CameraEffect(int, java.util.concurrent.Executor, androidx.camera.core.SurfaceProcessor, androidx.core.util.Consumer<java.lang.Throwable!>);
+ method public androidx.core.util.Consumer<java.lang.Throwable!> getErrorListener();
+ method public java.util.concurrent.Executor getExecutor();
+ method public androidx.camera.core.SurfaceProcessor? getSurfaceProcessor();
+ method public int getTargets();
+ field public static final int IMAGE_CAPTURE = 4; // 0x4
+ field public static final int PREVIEW = 1; // 0x1
+ field public static final int VIDEO_CAPTURE = 2; // 0x2
+ }
+
+ @RequiresApi(21) public interface CameraFilter {
+ method public java.util.List<androidx.camera.core.CameraInfo!> filter(java.util.List<androidx.camera.core.CameraInfo!>);
+ }
+
+ @RequiresApi(21) public interface CameraInfo {
+ method public androidx.camera.core.CameraSelector getCameraSelector();
+ method public androidx.lifecycle.LiveData<androidx.camera.core.CameraState!> getCameraState();
+ method public androidx.camera.core.ExposureState getExposureState();
+ method @FloatRange(from=0, fromInclusive=false) public default float getIntrinsicZoomRatio();
+ method public default int getLensFacing();
+ method public int getSensorRotationDegrees();
+ method public int getSensorRotationDegrees(int);
+ method public default java.util.Set<android.util.Range<java.lang.Integer!>!> getSupportedFrameRateRanges();
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+ method public boolean hasFlashUnit();
+ method public default boolean isFocusMeteringSupported(androidx.camera.core.FocusMeteringAction);
+ method @SuppressCompatibility @androidx.camera.core.ExperimentalZeroShutterLag public default boolean isZslSupported();
+ }
+
+ @RequiresApi(21) public final class CameraInfoUnavailableException extends java.lang.Exception {
+ }
+
+ @RequiresApi(21) public interface CameraProvider {
+ method public java.util.List<androidx.camera.core.CameraInfo!> getAvailableCameraInfos();
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ }
+
+ @RequiresApi(21) public final class CameraSelector {
+ method public java.util.List<androidx.camera.core.CameraInfo!> filter(java.util.List<androidx.camera.core.CameraInfo!>);
+ field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+ field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+ field public static final int LENS_FACING_BACK = 1; // 0x1
+ field @SuppressCompatibility @androidx.camera.core.ExperimentalLensFacing public static final int LENS_FACING_EXTERNAL = 2; // 0x2
+ field public static final int LENS_FACING_FRONT = 0; // 0x0
+ field public static final int LENS_FACING_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public static final class CameraSelector.Builder {
+ ctor public CameraSelector.Builder();
+ method public androidx.camera.core.CameraSelector.Builder addCameraFilter(androidx.camera.core.CameraFilter);
+ method public androidx.camera.core.CameraSelector build();
+ method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+ }
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class CameraState {
+ ctor public CameraState();
+ method public static androidx.camera.core.CameraState create(androidx.camera.core.CameraState.Type);
+ method public static androidx.camera.core.CameraState create(androidx.camera.core.CameraState.Type, androidx.camera.core.CameraState.StateError?);
+ method public abstract androidx.camera.core.CameraState.StateError? getError();
+ method public abstract androidx.camera.core.CameraState.Type getType();
+ field public static final int ERROR_CAMERA_DISABLED = 5; // 0x5
+ field public static final int ERROR_CAMERA_FATAL_ERROR = 6; // 0x6
+ field public static final int ERROR_CAMERA_IN_USE = 2; // 0x2
+ field public static final int ERROR_DO_NOT_DISTURB_MODE_ENABLED = 7; // 0x7
+ field public static final int ERROR_MAX_CAMERAS_IN_USE = 1; // 0x1
+ field public static final int ERROR_OTHER_RECOVERABLE_ERROR = 3; // 0x3
+ field public static final int ERROR_STREAM_CONFIG = 4; // 0x4
+ }
+
+ public enum CameraState.ErrorType {
+ enum_constant public static final androidx.camera.core.CameraState.ErrorType CRITICAL;
+ enum_constant public static final androidx.camera.core.CameraState.ErrorType RECOVERABLE;
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class CameraState.StateError {
+ ctor public CameraState.StateError();
+ method public static androidx.camera.core.CameraState.StateError create(int);
+ method public static androidx.camera.core.CameraState.StateError create(int, Throwable?);
+ method public abstract Throwable? getCause();
+ method public abstract int getCode();
+ method public androidx.camera.core.CameraState.ErrorType getType();
+ }
+
+ public enum CameraState.Type {
+ enum_constant public static final androidx.camera.core.CameraState.Type CLOSED;
+ enum_constant public static final androidx.camera.core.CameraState.Type CLOSING;
+ enum_constant public static final androidx.camera.core.CameraState.Type OPEN;
+ enum_constant public static final androidx.camera.core.CameraState.Type OPENING;
+ enum_constant public static final androidx.camera.core.CameraState.Type PENDING_OPEN;
+ }
+
+ @RequiresApi(21) public class CameraUnavailableException extends java.lang.Exception {
+ ctor public CameraUnavailableException(int);
+ ctor public CameraUnavailableException(int, String?);
+ ctor public CameraUnavailableException(int, String?, Throwable?);
+ ctor public CameraUnavailableException(int, Throwable?);
+ method public int getReason();
+ field public static final int CAMERA_DISABLED = 1; // 0x1
+ field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+ field public static final int CAMERA_ERROR = 3; // 0x3
+ field public static final int CAMERA_IN_USE = 4; // 0x4
+ field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+ field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+ field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ @RequiresApi(21) public final class CameraXConfig {
+ method public androidx.camera.core.CameraSelector? getAvailableCamerasLimiter(androidx.camera.core.CameraSelector?);
+ method public java.util.concurrent.Executor? getCameraExecutor(java.util.concurrent.Executor?);
+ method public int getMinimumLoggingLevel();
+ method public android.os.Handler? getSchedulerHandler(android.os.Handler?);
+ }
+
+ public static final class CameraXConfig.Builder {
+ method public androidx.camera.core.CameraXConfig build();
+ method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+ method public androidx.camera.core.CameraXConfig.Builder setAvailableCamerasLimiter(androidx.camera.core.CameraSelector);
+ method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.CameraXConfig.Builder setMinimumLoggingLevel(@IntRange(from=android.util.Log.DEBUG, to=android.util.Log.ERROR) int);
+ method public androidx.camera.core.CameraXConfig.Builder setSchedulerHandler(android.os.Handler);
+ }
+
+ public static interface CameraXConfig.Provider {
+ method public androidx.camera.core.CameraXConfig getCameraXConfig();
+ }
+
+ @RequiresApi(21) public class ConcurrentCamera {
+ ctor public ConcurrentCamera(java.util.List<androidx.camera.core.Camera!>);
+ method public java.util.List<androidx.camera.core.Camera!> getCameras();
+ }
+
+ public static final class ConcurrentCamera.SingleCameraConfig {
+ ctor public ConcurrentCamera.SingleCameraConfig(androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup, androidx.lifecycle.LifecycleOwner);
+ method public androidx.camera.core.CameraSelector getCameraSelector();
+ method public androidx.lifecycle.LifecycleOwner getLifecycleOwner();
+ method public androidx.camera.core.UseCaseGroup getUseCaseGroup();
+ }
+
+ @RequiresApi(21) public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+ }
+
+ @RequiresApi(21) public final class DynamicRange {
+ ctor public DynamicRange(int, int);
+ method public int getBitDepth();
+ method public int getEncoding();
+ field public static final int BIT_DEPTH_10_BIT = 10; // 0xa
+ field public static final int BIT_DEPTH_8_BIT = 8; // 0x8
+ field public static final int BIT_DEPTH_UNSPECIFIED = 0; // 0x0
+ field public static final androidx.camera.core.DynamicRange DOLBY_VISION_10_BIT;
+ field public static final androidx.camera.core.DynamicRange DOLBY_VISION_8_BIT;
+ field public static final int ENCODING_DOLBY_VISION = 6; // 0x6
+ field public static final int ENCODING_HDR10 = 4; // 0x4
+ field public static final int ENCODING_HDR10_PLUS = 5; // 0x5
+ field public static final int ENCODING_HDR_UNSPECIFIED = 2; // 0x2
+ field public static final int ENCODING_HLG = 3; // 0x3
+ field public static final int ENCODING_SDR = 1; // 0x1
+ field public static final int ENCODING_UNSPECIFIED = 0; // 0x0
+ field public static final androidx.camera.core.DynamicRange HDR10_10_BIT;
+ field public static final androidx.camera.core.DynamicRange HDR10_PLUS_10_BIT;
+ field public static final androidx.camera.core.DynamicRange HDR_UNSPECIFIED_10_BIT;
+ field public static final androidx.camera.core.DynamicRange HLG_10_BIT;
+ field public static final androidx.camera.core.DynamicRange SDR;
+ field public static final androidx.camera.core.DynamicRange UNSPECIFIED;
+ }
+
+ @SuppressCompatibility @RequiresApi(21) @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalLensFacing {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalUseCaseApi {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalZeroShutterLag {
+ }
+
+ @RequiresApi(21) public interface ExposureState {
+ method public int getExposureCompensationIndex();
+ method public android.util.Range<java.lang.Integer!> getExposureCompensationRange();
+ method public android.util.Rational getExposureCompensationStep();
+ method public boolean isExposureCompensationSupported();
+ }
+
+ @RequiresApi(21) public interface ExtendableBuilder<T> {
+ method public T build();
+ }
+
+ @RequiresApi(21) public final class FocusMeteringAction {
+ method public long getAutoCancelDurationInMillis();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+ method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+ method public boolean isAutoCancelEnabled();
+ field public static final int FLAG_AE = 2; // 0x2
+ field public static final int FLAG_AF = 1; // 0x1
+ field public static final int FLAG_AWB = 4; // 0x4
+ }
+
+ public static class FocusMeteringAction.Builder {
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+ ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+ method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+ method public androidx.camera.core.FocusMeteringAction build();
+ method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+ method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+ }
+
+ @RequiresApi(21) public final class FocusMeteringResult {
+ method public boolean isFocusSuccessful();
+ }
+
+ @RequiresApi(21) public final class ImageAnalysis extends androidx.camera.core.UseCase {
+ method public void clearAnalyzer();
+ method @SuppressCompatibility @androidx.camera.core.ExperimentalUseCaseApi public java.util.concurrent.Executor? getBackgroundExecutor();
+ method public int getBackpressureStrategy();
+ method public int getImageQueueDepth();
+ method public int getOutputImageFormat();
+ method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
+ method public int getTargetRotation();
+ method public boolean isOutputImageRotationEnabled();
+ method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method public void setTargetRotation(int);
+ field public static final int COORDINATE_SYSTEM_ORIGINAL = 0; // 0x0
+ field public static final int OUTPUT_IMAGE_FORMAT_RGBA_8888 = 2; // 0x2
+ field public static final int OUTPUT_IMAGE_FORMAT_YUV_420_888 = 1; // 0x1
+ field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+ field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+ }
+
+ public static interface ImageAnalysis.Analyzer {
+ method public void analyze(androidx.camera.core.ImageProxy);
+ method public default android.util.Size? getDefaultTargetResolution();
+ method public default int getTargetCoordinateSystem();
+ method public default void updateTransform(android.graphics.Matrix?);
+ }
+
+ public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+ ctor public ImageAnalysis.Builder();
+ method public androidx.camera.core.ImageAnalysis build();
+ method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setOutputImageFormat(int);
+ method @RequiresApi(23) public androidx.camera.core.ImageAnalysis.Builder setOutputImageRotationEnabled(boolean);
+ method public androidx.camera.core.ImageAnalysis.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+ method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+ method @Deprecated public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+ }
+
+ @RequiresApi(21) public final class ImageCapture extends androidx.camera.core.UseCase {
+ method public int getCaptureMode();
+ method public int getFlashMode();
+ method @IntRange(from=1, to=100) public int getJpegQuality();
+ method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
+ method public int getTargetRotation();
+ method public void setCropAspectRatio(android.util.Rational);
+ method public void setFlashMode(int);
+ method public void setTargetRotation(int);
+ method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+ field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+ field @SuppressCompatibility @androidx.camera.core.ExperimentalZeroShutterLag public static final int CAPTURE_MODE_ZERO_SHUTTER_LAG = 2; // 0x2
+ field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+ field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+ field public static final int ERROR_FILE_IO = 1; // 0x1
+ field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 0; // 0x0
+ field public static final int FLASH_MODE_AUTO = 0; // 0x0
+ field public static final int FLASH_MODE_OFF = 2; // 0x2
+ field public static final int FLASH_MODE_ON = 1; // 0x1
+ }
+
+ public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+ ctor public ImageCapture.Builder();
+ method public androidx.camera.core.ImageCapture build();
+ method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+ method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.core.ImageCapture.Builder setJpegQuality(@IntRange(from=1, to=100) int);
+ method public androidx.camera.core.ImageCapture.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+ method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+ method @Deprecated public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+ }
+
+ public static final class ImageCapture.Metadata {
+ ctor public ImageCapture.Metadata();
+ method public android.location.Location? getLocation();
+ method public boolean isReversedHorizontal();
+ method public boolean isReversedVertical();
+ method public void setLocation(android.location.Location?);
+ method public void setReversedHorizontal(boolean);
+ method public void setReversedVertical(boolean);
+ }
+
+ public abstract static class ImageCapture.OnImageCapturedCallback {
+ ctor public ImageCapture.OnImageCapturedCallback();
+ method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ }
+
+ public static interface ImageCapture.OnImageSavedCallback {
+ method public void onError(androidx.camera.core.ImageCaptureException);
+ method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+ }
+
+ public static final class ImageCapture.OutputFileOptions {
+ }
+
+ public static final class ImageCapture.OutputFileOptions.Builder {
+ ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+ ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+ method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+ method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+ }
+
+ public static class ImageCapture.OutputFileResults {
+ method public android.net.Uri? getSavedUri();
+ }
+
+ @RequiresApi(21) public class ImageCaptureException extends java.lang.Exception {
+ ctor public ImageCaptureException(int, String, Throwable?);
+ method public int getImageCaptureError();
+ }
+
+ @RequiresApi(21) public interface ImageInfo {
+ method public int getRotationDegrees();
+ method public default android.graphics.Matrix getSensorToBufferTransformMatrix();
+ method public long getTimestamp();
+ }
+
+ public interface ImageProcessor {
+ method public androidx.camera.core.ImageProcessor.Response process(androidx.camera.core.ImageProcessor.Request) throws androidx.camera.core.ProcessingException;
+ }
+
+ public static interface ImageProcessor.Request {
+ method public androidx.camera.core.ImageProxy getInputImage();
+ method public int getOutputFormat();
+ }
+
+ public static interface ImageProcessor.Response {
+ method public androidx.camera.core.ImageProxy getOutputImage();
+ }
+
+ @RequiresApi(21) public interface ImageProxy extends java.lang.AutoCloseable {
+ method public void close();
+ method public android.graphics.Rect getCropRect();
+ method public int getFormat();
+ method public int getHeight();
+ method @SuppressCompatibility @androidx.camera.core.ExperimentalGetImage public android.media.Image? getImage();
+ method public androidx.camera.core.ImageInfo getImageInfo();
+ method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+ method public int getWidth();
+ method public void setCropRect(android.graphics.Rect?);
+ method public default android.graphics.Bitmap toBitmap();
+ }
+
+ public static interface ImageProxy.PlaneProxy {
+ method public java.nio.ByteBuffer getBuffer();
+ method public int getPixelStride();
+ method public int getRowStride();
+ }
+
+ @RequiresApi(21) public class InitializationException extends java.lang.Exception {
+ ctor public InitializationException(String?);
+ ctor public InitializationException(String?, Throwable?);
+ ctor public InitializationException(Throwable?);
+ }
+
+ @RequiresApi(21) public class MeteringPoint {
+ method public float getSize();
+ }
+
+ @RequiresApi(21) public abstract class MeteringPointFactory {
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+ method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+ method public static float getDefaultPointSize();
+ }
+
+ @RequiresApi(21) public class MirrorMode {
+ field public static final int MIRROR_MODE_OFF = 0; // 0x0
+ field public static final int MIRROR_MODE_ON = 1; // 0x1
+ field public static final int MIRROR_MODE_ON_FRONT_ONLY = 2; // 0x2
+ }
+
+ @RequiresApi(21) public final class Preview extends androidx.camera.core.UseCase {
+ method public androidx.camera.core.ResolutionInfo? getResolutionInfo();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector? getResolutionSelector();
+ method public android.util.Range<java.lang.Integer!> getTargetFrameRate();
+ method public int getTargetRotation();
+ method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+ method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+ method public void setTargetRotation(int);
+ }
+
+ public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+ ctor public Preview.Builder();
+ method public androidx.camera.core.Preview build();
+ method public androidx.camera.core.Preview.Builder setResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector);
+ method @Deprecated public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+ method public androidx.camera.core.Preview.Builder setTargetFrameRate(android.util.Range<java.lang.Integer!>);
+ method public androidx.camera.core.Preview.Builder setTargetName(String);
+ method @Deprecated public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+ method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+ }
+
+ public static interface Preview.SurfaceProvider {
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ }
+
+ public class ProcessingException extends java.lang.Exception {
+ ctor public ProcessingException();
+ }
+
+ @RequiresApi(21) public class ResolutionInfo {
+ ctor public ResolutionInfo(android.util.Size, android.graphics.Rect, int);
+ method public android.graphics.Rect getCropRect();
+ method public android.util.Size getResolution();
+ method public int getRotationDegrees();
+ }
+
+ @RequiresApi(21) public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+ ctor public SurfaceOrientedMeteringPointFactory(float, float);
+ ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+ }
+
+ public interface SurfaceOutput extends java.io.Closeable {
+ method public void close();
+ method public android.util.Size getSize();
+ method public android.view.Surface getSurface(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceOutput.Event!>);
+ method public int getTargets();
+ method public void updateTransformMatrix(float[], float[]);
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceOutput.Event {
+ method public abstract int getEventCode();
+ method public abstract androidx.camera.core.SurfaceOutput getSurfaceOutput();
+ field public static final int EVENT_REQUEST_CLOSE = 0; // 0x0
+ }
+
+ public interface SurfaceProcessor {
+ method public void onInputSurface(androidx.camera.core.SurfaceRequest) throws androidx.camera.core.ProcessingException;
+ method public void onOutputSurface(androidx.camera.core.SurfaceOutput) throws androidx.camera.core.ProcessingException;
+ }
+
+ @RequiresApi(21) public final class SurfaceRequest {
+ method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+ method public void clearTransformationInfoListener();
+ method public androidx.camera.core.DynamicRange getDynamicRange();
+ method public android.util.Size getResolution();
+ method public boolean invalidate();
+ method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+ method public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
+ method public boolean willNotProvideSurface();
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+ method public abstract int getResultCode();
+ method public abstract android.view.Surface getSurface();
+ field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+ field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+ field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+ field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+ field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+ }
+
+ @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
+ method public abstract android.graphics.Rect getCropRect();
+ method public abstract int getRotationDegrees();
+ }
+
+ public static interface SurfaceRequest.TransformationInfoListener {
+ method public void onTransformationInfoUpdate(androidx.camera.core.SurfaceRequest.TransformationInfo);
+ }
+
+ @RequiresApi(21) public class TorchState {
+ field public static final int OFF = 0; // 0x0
+ field public static final int ON = 1; // 0x1
+ }
+
+ @RequiresApi(21) public abstract class UseCase {
+ method public static int snapToSurfaceRotation(@IntRange(from=0, to=359) int);
+ }
+
+ @RequiresApi(21) public final class UseCaseGroup {
+ method public java.util.List<androidx.camera.core.CameraEffect!> getEffects();
+ method public java.util.List<androidx.camera.core.UseCase!> getUseCases();
+ method public androidx.camera.core.ViewPort? getViewPort();
+ }
+
+ public static final class UseCaseGroup.Builder {
+ ctor public UseCaseGroup.Builder();
+ method public androidx.camera.core.UseCaseGroup.Builder addEffect(androidx.camera.core.CameraEffect);
+ method public androidx.camera.core.UseCaseGroup.Builder addUseCase(androidx.camera.core.UseCase);
+ method public androidx.camera.core.UseCaseGroup build();
+ method public androidx.camera.core.UseCaseGroup.Builder setViewPort(androidx.camera.core.ViewPort);
+ }
+
+ @RequiresApi(21) public final class ViewPort {
+ method public android.util.Rational getAspectRatio();
+ method public int getLayoutDirection();
+ method public int getRotation();
+ method public int getScaleType();
+ field public static final int FILL_CENTER = 1; // 0x1
+ field public static final int FILL_END = 2; // 0x2
+ field public static final int FILL_START = 0; // 0x0
+ field public static final int FIT = 3; // 0x3
+ }
+
+ public static final class ViewPort.Builder {
+ ctor public ViewPort.Builder(android.util.Rational, int);
+ method public androidx.camera.core.ViewPort build();
+ method public androidx.camera.core.ViewPort.Builder setLayoutDirection(int);
+ method public androidx.camera.core.ViewPort.Builder setScaleType(int);
+ }
+
+ @RequiresApi(21) public interface ZoomState {
+ method public float getLinearZoom();
+ method public float getMaxZoomRatio();
+ method public float getMinZoomRatio();
+ method public float getZoomRatio();
+ }
+
+}
+
+package androidx.camera.core.resolutionselector {
+
+ @RequiresApi(21) public final class AspectRatioStrategy {
+ ctor public AspectRatioStrategy(int, int);
+ method public int getFallbackRule();
+ method public int getPreferredAspectRatio();
+ field public static final int FALLBACK_RULE_AUTO = 1; // 0x1
+ field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+ field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_16_9_FALLBACK_AUTO_STRATEGY;
+ field public static final androidx.camera.core.resolutionselector.AspectRatioStrategy RATIO_4_3_FALLBACK_AUTO_STRATEGY;
+ }
+
+ @RequiresApi(21) public interface ResolutionFilter {
+ method public java.util.List<android.util.Size!> filter(java.util.List<android.util.Size!>, int);
+ }
+
+ @RequiresApi(21) public final class ResolutionSelector {
+ method public int getAllowedResolutionMode();
+ method public androidx.camera.core.resolutionselector.AspectRatioStrategy getAspectRatioStrategy();
+ method public androidx.camera.core.resolutionselector.ResolutionFilter? getResolutionFilter();
+ method public androidx.camera.core.resolutionselector.ResolutionStrategy? getResolutionStrategy();
+ field public static final int PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION = 0; // 0x0
+ field public static final int PREFER_HIGHER_RESOLUTION_OVER_CAPTURE_RATE = 1; // 0x1
+ }
+
+ public static final class ResolutionSelector.Builder {
+ ctor public ResolutionSelector.Builder();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector build();
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setAllowedResolutionMode(int);
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setAspectRatioStrategy(androidx.camera.core.resolutionselector.AspectRatioStrategy);
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionFilter(androidx.camera.core.resolutionselector.ResolutionFilter);
+ method public androidx.camera.core.resolutionselector.ResolutionSelector.Builder setResolutionStrategy(androidx.camera.core.resolutionselector.ResolutionStrategy);
+ }
+
+ @RequiresApi(21) public final class ResolutionStrategy {
+ ctor public ResolutionStrategy(android.util.Size, int);
+ method public android.util.Size? getBoundSize();
+ method public int getFallbackRule();
+ field public static final int FALLBACK_RULE_CLOSEST_HIGHER = 2; // 0x2
+ field public static final int FALLBACK_RULE_CLOSEST_HIGHER_THEN_LOWER = 1; // 0x1
+ field public static final int FALLBACK_RULE_CLOSEST_LOWER = 4; // 0x4
+ field public static final int FALLBACK_RULE_CLOSEST_LOWER_THEN_HIGHER = 3; // 0x3
+ field public static final int FALLBACK_RULE_NONE = 0; // 0x0
+ field public static final androidx.camera.core.resolutionselector.ResolutionStrategy HIGHEST_AVAILABLE_STRATEGY;
+ }
+
+}
+
diff --git a/camera/camera-effects-still-portrait/api/1.3.0-beta03.txt b/camera/camera-effects-still-portrait/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-effects-still-portrait/api/1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-effects-still-portrait/api/res-1.3.0-beta03.txt b/camera/camera-effects-still-portrait/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-effects-still-portrait/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-effects-still-portrait/api/restricted_1.3.0-beta03.txt b/camera/camera-effects-still-portrait/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-effects-still-portrait/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-effects/api/1.3.0-beta03.txt b/camera/camera-effects/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-effects/api/1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-effects/api/res-1.3.0-beta03.txt b/camera/camera-effects/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-effects/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-effects/api/restricted_1.3.0-beta03.txt b/camera/camera-effects/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-effects/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-extensions/api/1.3.0-beta03.txt b/camera/camera-extensions/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..5c6e740
--- /dev/null
+++ b/camera/camera-extensions/api/1.3.0-beta03.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.camera.extensions {
+
+ @RequiresApi(21) public final class ExtensionMode {
+ field public static final int AUTO = 5; // 0x5
+ field public static final int BOKEH = 1; // 0x1
+ field public static final int FACE_RETOUCH = 4; // 0x4
+ field public static final int HDR = 2; // 0x2
+ field public static final int NIGHT = 3; // 0x3
+ field public static final int NONE = 0; // 0x0
+ }
+
+ @RequiresApi(21) public final class ExtensionsManager {
+ method public android.util.Range<java.lang.Long!>? getEstimatedCaptureLatencyRange(androidx.camera.core.CameraSelector, int);
+ method public androidx.camera.core.CameraSelector getExtensionEnabledCameraSelector(androidx.camera.core.CameraSelector, int);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.extensions.ExtensionsManager!> getInstanceAsync(android.content.Context, androidx.camera.core.CameraProvider);
+ method public boolean isExtensionAvailable(androidx.camera.core.CameraSelector, int);
+ method public boolean isImageAnalysisSupported(androidx.camera.core.CameraSelector, int);
+ }
+
+}
+
diff --git a/camera/camera-extensions/api/res-1.3.0-beta03.txt b/camera/camera-extensions/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-extensions/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-extensions/api/restricted_1.3.0-beta03.txt b/camera/camera-extensions/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..5c6e740
--- /dev/null
+++ b/camera/camera-extensions/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,22 @@
+// Signature format: 4.0
+package androidx.camera.extensions {
+
+ @RequiresApi(21) public final class ExtensionMode {
+ field public static final int AUTO = 5; // 0x5
+ field public static final int BOKEH = 1; // 0x1
+ field public static final int FACE_RETOUCH = 4; // 0x4
+ field public static final int HDR = 2; // 0x2
+ field public static final int NIGHT = 3; // 0x3
+ field public static final int NONE = 0; // 0x0
+ }
+
+ @RequiresApi(21) public final class ExtensionsManager {
+ method public android.util.Range<java.lang.Long!>? getEstimatedCaptureLatencyRange(androidx.camera.core.CameraSelector, int);
+ method public androidx.camera.core.CameraSelector getExtensionEnabledCameraSelector(androidx.camera.core.CameraSelector, int);
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.extensions.ExtensionsManager!> getInstanceAsync(android.content.Context, androidx.camera.core.CameraProvider);
+ method public boolean isExtensionAvailable(androidx.camera.core.CameraSelector, int);
+ method public boolean isImageAnalysisSupported(androidx.camera.core.CameraSelector, int);
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/1.3.0-beta03.txt b/camera/camera-lifecycle/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..d0621cb
--- /dev/null
+++ b/camera/camera-lifecycle/api/1.3.0-beta03.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.camera.lifecycle {
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCameraProviderConfiguration {
+ }
+
+ @RequiresApi(21) public final class ProcessCameraProvider implements androidx.camera.core.CameraProvider {
+ method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
+ method @MainThread public androidx.camera.core.ConcurrentCamera bindToLifecycle(java.util.List<androidx.camera.core.ConcurrentCamera.SingleCameraConfig!>);
+ method @SuppressCompatibility @androidx.camera.lifecycle.ExperimentalCameraProviderConfiguration public static void configureInstance(androidx.camera.core.CameraXConfig);
+ method public java.util.List<androidx.camera.core.CameraInfo!> getAvailableCameraInfos();
+ method public java.util.List<java.util.List<androidx.camera.core.CameraInfo!>!> getAvailableConcurrentCameraInfos();
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method @MainThread public boolean isConcurrentCameraModeOn();
+ method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+ method @MainThread public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-lifecycle/api/res-1.3.0-beta03.txt b/camera/camera-lifecycle/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-lifecycle/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-lifecycle/api/restricted_1.3.0-beta03.txt b/camera/camera-lifecycle/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..d0621cb
--- /dev/null
+++ b/camera/camera-lifecycle/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,23 @@
+// Signature format: 4.0
+package androidx.camera.lifecycle {
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCameraProviderConfiguration {
+ }
+
+ @RequiresApi(21) public final class ProcessCameraProvider implements androidx.camera.core.CameraProvider {
+ method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+ method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
+ method @MainThread public androidx.camera.core.ConcurrentCamera bindToLifecycle(java.util.List<androidx.camera.core.ConcurrentCamera.SingleCameraConfig!>);
+ method @SuppressCompatibility @androidx.camera.lifecycle.ExperimentalCameraProviderConfiguration public static void configureInstance(androidx.camera.core.CameraXConfig);
+ method public java.util.List<androidx.camera.core.CameraInfo!> getAvailableCameraInfos();
+ method public java.util.List<java.util.List<androidx.camera.core.CameraInfo!>!> getAvailableConcurrentCameraInfos();
+ method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+ method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+ method public boolean isBound(androidx.camera.core.UseCase);
+ method @MainThread public boolean isConcurrentCameraModeOn();
+ method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+ method @MainThread public void unbindAll();
+ }
+
+}
+
diff --git a/camera/camera-mlkit-vision/api/1.3.0-beta03.txt b/camera/camera-mlkit-vision/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..0599c25
--- /dev/null
+++ b/camera/camera-mlkit-vision/api/1.3.0-beta03.txt
@@ -0,0 +1,20 @@
+// Signature format: 4.0
+package androidx.camera.mlkit.vision {
+
+ @RequiresApi(21) public class MlKitAnalyzer implements androidx.camera.core.ImageAnalysis.Analyzer {
+ ctor public MlKitAnalyzer(java.util.List<com.google.mlkit.vision.interfaces.Detector<?>!>, int, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.mlkit.vision.MlKitAnalyzer.Result!>);
+ method public final void analyze(androidx.camera.core.ImageProxy);
+ method public final android.util.Size getDefaultTargetResolution();
+ method public final int getTargetCoordinateSystem();
+ method public final void updateTransform(android.graphics.Matrix?);
+ }
+
+ public static final class MlKitAnalyzer.Result {
+ ctor public MlKitAnalyzer.Result(java.util.Map<com.google.mlkit.vision.interfaces.Detector<?>!,java.lang.Object!>, long, java.util.Map<com.google.mlkit.vision.interfaces.Detector<?>!,java.lang.Throwable!>);
+ method public Throwable? getThrowable(com.google.mlkit.vision.interfaces.Detector<?>);
+ method public long getTimestamp();
+ method public <T> T? getValue(com.google.mlkit.vision.interfaces.Detector<T!>);
+ }
+
+}
+
diff --git a/camera/camera-mlkit-vision/api/res-1.3.0-beta03.txt b/camera/camera-mlkit-vision/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-mlkit-vision/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-mlkit-vision/api/restricted_1.3.0-beta03.txt b/camera/camera-mlkit-vision/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..0599c25
--- /dev/null
+++ b/camera/camera-mlkit-vision/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,20 @@
+// Signature format: 4.0
+package androidx.camera.mlkit.vision {
+
+ @RequiresApi(21) public class MlKitAnalyzer implements androidx.camera.core.ImageAnalysis.Analyzer {
+ ctor public MlKitAnalyzer(java.util.List<com.google.mlkit.vision.interfaces.Detector<?>!>, int, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.mlkit.vision.MlKitAnalyzer.Result!>);
+ method public final void analyze(androidx.camera.core.ImageProxy);
+ method public final android.util.Size getDefaultTargetResolution();
+ method public final int getTargetCoordinateSystem();
+ method public final void updateTransform(android.graphics.Matrix?);
+ }
+
+ public static final class MlKitAnalyzer.Result {
+ ctor public MlKitAnalyzer.Result(java.util.Map<com.google.mlkit.vision.interfaces.Detector<?>!,java.lang.Object!>, long, java.util.Map<com.google.mlkit.vision.interfaces.Detector<?>!,java.lang.Throwable!>);
+ method public Throwable? getThrowable(com.google.mlkit.vision.interfaces.Detector<?>);
+ method public long getTimestamp();
+ method public <T> T? getValue(com.google.mlkit.vision.interfaces.Detector<T!>);
+ }
+
+}
+
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
index 86ce8a9..4f64bb4 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraControl.java
@@ -193,8 +193,8 @@
@NonNull
@Override
- public ListenableFuture<Integer> setExposureCompensationIndex(int exposure) {
- mExposureCompensation = exposure;
+ public ListenableFuture<Integer> setExposureCompensationIndex(int value) {
+ mExposureCompensation = value;
return Futures.immediateFuture(null);
}
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java
index 904e34e..c3c8932 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/impl/mocks/MockConsumer.java
@@ -261,8 +261,8 @@
}
@Override
- public void accept(T event) {
- mEventList.add(event);
+ public void accept(T t) {
+ mEventList.add(t);
synchronized (mLock) {
if (mLatch != null && isVerified(mEventList)) {
diff --git a/camera/camera-video/api/1.3.0-beta03.txt b/camera/camera-video/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..b9cc77a
--- /dev/null
+++ b/camera/camera-video/api/1.3.0-beta03.txt
@@ -0,0 +1,207 @@
+// Signature format: 4.0
+package androidx.camera.video {
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class AudioStats {
+ method public abstract int getAudioState();
+ method public abstract Throwable? getErrorCause();
+ method public boolean hasAudio();
+ method public boolean hasError();
+ field public static final int AUDIO_STATE_ACTIVE = 0; // 0x0
+ field public static final int AUDIO_STATE_DISABLED = 1; // 0x1
+ field public static final int AUDIO_STATE_ENCODER_ERROR = 3; // 0x3
+ field public static final int AUDIO_STATE_MUTED = 5; // 0x5
+ field public static final int AUDIO_STATE_SOURCE_ERROR = 4; // 0x4
+ field public static final int AUDIO_STATE_SOURCE_SILENCED = 2; // 0x2
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalPersistentRecording {
+ }
+
+ @RequiresApi(21) public class FallbackStrategy {
+ method public static androidx.camera.video.FallbackStrategy higherQualityOrLowerThan(androidx.camera.video.Quality);
+ method public static androidx.camera.video.FallbackStrategy higherQualityThan(androidx.camera.video.Quality);
+ method public static androidx.camera.video.FallbackStrategy lowerQualityOrHigherThan(androidx.camera.video.Quality);
+ method public static androidx.camera.video.FallbackStrategy lowerQualityThan(androidx.camera.video.Quality);
+ }
+
+ @RequiresApi(21) public final class FileDescriptorOutputOptions extends androidx.camera.video.OutputOptions {
+ method public android.os.ParcelFileDescriptor getParcelFileDescriptor();
+ }
+
+ @RequiresApi(21) public static final class FileDescriptorOutputOptions.Builder {
+ ctor public FileDescriptorOutputOptions.Builder(android.os.ParcelFileDescriptor);
+ method public androidx.camera.video.FileDescriptorOutputOptions build();
+ method public androidx.camera.video.FileDescriptorOutputOptions.Builder setDurationLimitMillis(@IntRange(from=0) long);
+ method public androidx.camera.video.FileDescriptorOutputOptions.Builder setFileSizeLimit(@IntRange(from=0) long);
+ method public androidx.camera.video.FileDescriptorOutputOptions.Builder setLocation(android.location.Location?);
+ }
+
+ @RequiresApi(21) public final class FileOutputOptions extends androidx.camera.video.OutputOptions {
+ method public java.io.File getFile();
+ }
+
+ @RequiresApi(21) public static final class FileOutputOptions.Builder {
+ ctor public FileOutputOptions.Builder(java.io.File);
+ method public androidx.camera.video.FileOutputOptions build();
+ method public androidx.camera.video.FileOutputOptions.Builder setDurationLimitMillis(@IntRange(from=0) long);
+ method public androidx.camera.video.FileOutputOptions.Builder setFileSizeLimit(@IntRange(from=0) long);
+ method public androidx.camera.video.FileOutputOptions.Builder setLocation(android.location.Location?);
+ }
+
+ @RequiresApi(21) public final class MediaStoreOutputOptions extends androidx.camera.video.OutputOptions {
+ method public android.net.Uri getCollectionUri();
+ method public android.content.ContentResolver getContentResolver();
+ method public android.content.ContentValues getContentValues();
+ field public static final android.content.ContentValues EMPTY_CONTENT_VALUES;
+ }
+
+ public static final class MediaStoreOutputOptions.Builder {
+ ctor public MediaStoreOutputOptions.Builder(android.content.ContentResolver, android.net.Uri);
+ method public androidx.camera.video.MediaStoreOutputOptions build();
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setContentValues(android.content.ContentValues);
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setDurationLimitMillis(@IntRange(from=0) long);
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setFileSizeLimit(@IntRange(from=0) long);
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setLocation(android.location.Location?);
+ }
+
+ @RequiresApi(21) public abstract class OutputOptions {
+ method @IntRange(from=0) public long getDurationLimitMillis();
+ method @IntRange(from=0) public long getFileSizeLimit();
+ method public android.location.Location? getLocation();
+ field public static final int DURATION_UNLIMITED = 0; // 0x0
+ field public static final int FILE_SIZE_UNLIMITED = 0; // 0x0
+ }
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class OutputResults {
+ ctor public OutputResults();
+ method public abstract android.net.Uri getOutputUri();
+ }
+
+ @RequiresApi(21) public final class PendingRecording {
+ method @SuppressCompatibility @androidx.camera.video.ExperimentalPersistentRecording public androidx.camera.video.PendingRecording asPersistentRecording();
+ method @CheckResult public androidx.camera.video.Recording start(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public androidx.camera.video.PendingRecording withAudioEnabled();
+ }
+
+ @RequiresApi(21) public class Quality {
+ field public static final androidx.camera.video.Quality FHD;
+ field public static final androidx.camera.video.Quality HD;
+ field public static final androidx.camera.video.Quality HIGHEST;
+ field public static final androidx.camera.video.Quality LOWEST;
+ field public static final androidx.camera.video.Quality SD;
+ field public static final androidx.camera.video.Quality UHD;
+ }
+
+ @RequiresApi(21) public final class QualitySelector {
+ method public static androidx.camera.video.QualitySelector from(androidx.camera.video.Quality);
+ method public static androidx.camera.video.QualitySelector from(androidx.camera.video.Quality, androidx.camera.video.FallbackStrategy);
+ method public static androidx.camera.video.QualitySelector fromOrderedList(java.util.List<androidx.camera.video.Quality!>);
+ method public static androidx.camera.video.QualitySelector fromOrderedList(java.util.List<androidx.camera.video.Quality!>, androidx.camera.video.FallbackStrategy);
+ method public static android.util.Size? getResolution(androidx.camera.core.CameraInfo, androidx.camera.video.Quality);
+ method @Deprecated public static java.util.List<androidx.camera.video.Quality!> getSupportedQualities(androidx.camera.core.CameraInfo);
+ method @Deprecated public static boolean isQualitySupported(androidx.camera.core.CameraInfo, androidx.camera.video.Quality);
+ }
+
+ @RequiresApi(21) public final class Recorder implements androidx.camera.video.VideoOutput {
+ method public int getAspectRatio();
+ method public java.util.concurrent.Executor? getExecutor();
+ method public androidx.camera.video.QualitySelector getQualitySelector();
+ method public int getTargetVideoEncodingBitRate();
+ method public static androidx.camera.video.VideoCapabilities getVideoCapabilities(androidx.camera.core.CameraInfo);
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ method @RequiresApi(26) public androidx.camera.video.PendingRecording prepareRecording(android.content.Context, androidx.camera.video.FileDescriptorOutputOptions);
+ method public androidx.camera.video.PendingRecording prepareRecording(android.content.Context, androidx.camera.video.FileOutputOptions);
+ method public androidx.camera.video.PendingRecording prepareRecording(android.content.Context, androidx.camera.video.MediaStoreOutputOptions);
+ field public static final androidx.camera.video.QualitySelector DEFAULT_QUALITY_SELECTOR;
+ }
+
+ @RequiresApi(21) public static final class Recorder.Builder {
+ ctor public Recorder.Builder();
+ method public androidx.camera.video.Recorder build();
+ method public androidx.camera.video.Recorder.Builder setAspectRatio(int);
+ method public androidx.camera.video.Recorder.Builder setExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.video.Recorder.Builder setQualitySelector(androidx.camera.video.QualitySelector);
+ method public androidx.camera.video.Recorder.Builder setTargetVideoEncodingBitRate(@IntRange(from=1) int);
+ }
+
+ @RequiresApi(21) public final class Recording implements java.lang.AutoCloseable {
+ method public void close();
+ method @SuppressCompatibility @androidx.camera.video.ExperimentalPersistentRecording public boolean isPersistent();
+ method public void mute(boolean);
+ method public void pause();
+ method public void resume();
+ method public void stop();
+ }
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class RecordingStats {
+ method public abstract androidx.camera.video.AudioStats getAudioStats();
+ method public abstract long getNumBytesRecorded();
+ method public abstract long getRecordedDurationNanos();
+ }
+
+ @RequiresApi(21) public interface VideoCapabilities {
+ method public java.util.Set<androidx.camera.core.DynamicRange!> getSupportedDynamicRanges();
+ method public java.util.List<androidx.camera.video.Quality!> getSupportedQualities(androidx.camera.core.DynamicRange);
+ method public boolean isQualitySupported(androidx.camera.video.Quality, androidx.camera.core.DynamicRange);
+ }
+
+ @RequiresApi(21) public final class VideoCapture<T extends androidx.camera.video.VideoOutput> extends androidx.camera.core.UseCase {
+ method public androidx.camera.core.DynamicRange getDynamicRange();
+ method public int getMirrorMode();
+ method public T getOutput();
+ method public android.util.Range<java.lang.Integer!> getTargetFrameRate();
+ method public int getTargetRotation();
+ method public void setTargetRotation(int);
+ method public static <T extends androidx.camera.video.VideoOutput> androidx.camera.video.VideoCapture<T!> withOutput(T);
+ }
+
+ @RequiresApi(21) public static final class VideoCapture.Builder<T extends androidx.camera.video.VideoOutput> implements androidx.camera.core.ExtendableBuilder<androidx.camera.video.VideoCapture> {
+ ctor public VideoCapture.Builder(T);
+ method public androidx.camera.video.VideoCapture<T!> build();
+ method public androidx.camera.video.VideoCapture.Builder<T!> setDynamicRange(androidx.camera.core.DynamicRange);
+ method public androidx.camera.video.VideoCapture.Builder<T!> setMirrorMode(int);
+ method public androidx.camera.video.VideoCapture.Builder<T!> setTargetFrameRate(android.util.Range<java.lang.Integer!>);
+ method public androidx.camera.video.VideoCapture.Builder<T!> setTargetRotation(int);
+ }
+
+ @RequiresApi(21) public interface VideoOutput {
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ }
+
+ @RequiresApi(21) public abstract class VideoRecordEvent {
+ method public androidx.camera.video.OutputOptions getOutputOptions();
+ method public androidx.camera.video.RecordingStats getRecordingStats();
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Finalize extends androidx.camera.video.VideoRecordEvent {
+ method public Throwable? getCause();
+ method public int getError();
+ method public androidx.camera.video.OutputResults getOutputResults();
+ method public boolean hasError();
+ field public static final int ERROR_DURATION_LIMIT_REACHED = 9; // 0x9
+ field public static final int ERROR_ENCODING_FAILED = 6; // 0x6
+ field public static final int ERROR_FILE_SIZE_LIMIT_REACHED = 2; // 0x2
+ field public static final int ERROR_INSUFFICIENT_STORAGE = 3; // 0x3
+ field public static final int ERROR_INVALID_OUTPUT_OPTIONS = 5; // 0x5
+ field public static final int ERROR_NONE = 0; // 0x0
+ field public static final int ERROR_NO_VALID_DATA = 8; // 0x8
+ field public static final int ERROR_RECORDER_ERROR = 7; // 0x7
+ field public static final int ERROR_RECORDING_GARBAGE_COLLECTED = 10; // 0xa
+ field public static final int ERROR_SOURCE_INACTIVE = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 1; // 0x1
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Pause extends androidx.camera.video.VideoRecordEvent {
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Resume extends androidx.camera.video.VideoRecordEvent {
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Start extends androidx.camera.video.VideoRecordEvent {
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Status extends androidx.camera.video.VideoRecordEvent {
+ }
+
+}
+
diff --git a/camera/camera-video/api/res-1.3.0-beta03.txt b/camera/camera-video/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-video/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-video/api/restricted_1.3.0-beta03.txt b/camera/camera-video/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..b9cc77a
--- /dev/null
+++ b/camera/camera-video/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,207 @@
+// Signature format: 4.0
+package androidx.camera.video {
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class AudioStats {
+ method public abstract int getAudioState();
+ method public abstract Throwable? getErrorCause();
+ method public boolean hasAudio();
+ method public boolean hasError();
+ field public static final int AUDIO_STATE_ACTIVE = 0; // 0x0
+ field public static final int AUDIO_STATE_DISABLED = 1; // 0x1
+ field public static final int AUDIO_STATE_ENCODER_ERROR = 3; // 0x3
+ field public static final int AUDIO_STATE_MUTED = 5; // 0x5
+ field public static final int AUDIO_STATE_SOURCE_ERROR = 4; // 0x4
+ field public static final int AUDIO_STATE_SOURCE_SILENCED = 2; // 0x2
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalPersistentRecording {
+ }
+
+ @RequiresApi(21) public class FallbackStrategy {
+ method public static androidx.camera.video.FallbackStrategy higherQualityOrLowerThan(androidx.camera.video.Quality);
+ method public static androidx.camera.video.FallbackStrategy higherQualityThan(androidx.camera.video.Quality);
+ method public static androidx.camera.video.FallbackStrategy lowerQualityOrHigherThan(androidx.camera.video.Quality);
+ method public static androidx.camera.video.FallbackStrategy lowerQualityThan(androidx.camera.video.Quality);
+ }
+
+ @RequiresApi(21) public final class FileDescriptorOutputOptions extends androidx.camera.video.OutputOptions {
+ method public android.os.ParcelFileDescriptor getParcelFileDescriptor();
+ }
+
+ @RequiresApi(21) public static final class FileDescriptorOutputOptions.Builder {
+ ctor public FileDescriptorOutputOptions.Builder(android.os.ParcelFileDescriptor);
+ method public androidx.camera.video.FileDescriptorOutputOptions build();
+ method public androidx.camera.video.FileDescriptorOutputOptions.Builder setDurationLimitMillis(@IntRange(from=0) long);
+ method public androidx.camera.video.FileDescriptorOutputOptions.Builder setFileSizeLimit(@IntRange(from=0) long);
+ method public androidx.camera.video.FileDescriptorOutputOptions.Builder setLocation(android.location.Location?);
+ }
+
+ @RequiresApi(21) public final class FileOutputOptions extends androidx.camera.video.OutputOptions {
+ method public java.io.File getFile();
+ }
+
+ @RequiresApi(21) public static final class FileOutputOptions.Builder {
+ ctor public FileOutputOptions.Builder(java.io.File);
+ method public androidx.camera.video.FileOutputOptions build();
+ method public androidx.camera.video.FileOutputOptions.Builder setDurationLimitMillis(@IntRange(from=0) long);
+ method public androidx.camera.video.FileOutputOptions.Builder setFileSizeLimit(@IntRange(from=0) long);
+ method public androidx.camera.video.FileOutputOptions.Builder setLocation(android.location.Location?);
+ }
+
+ @RequiresApi(21) public final class MediaStoreOutputOptions extends androidx.camera.video.OutputOptions {
+ method public android.net.Uri getCollectionUri();
+ method public android.content.ContentResolver getContentResolver();
+ method public android.content.ContentValues getContentValues();
+ field public static final android.content.ContentValues EMPTY_CONTENT_VALUES;
+ }
+
+ public static final class MediaStoreOutputOptions.Builder {
+ ctor public MediaStoreOutputOptions.Builder(android.content.ContentResolver, android.net.Uri);
+ method public androidx.camera.video.MediaStoreOutputOptions build();
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setContentValues(android.content.ContentValues);
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setDurationLimitMillis(@IntRange(from=0) long);
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setFileSizeLimit(@IntRange(from=0) long);
+ method public androidx.camera.video.MediaStoreOutputOptions.Builder setLocation(android.location.Location?);
+ }
+
+ @RequiresApi(21) public abstract class OutputOptions {
+ method @IntRange(from=0) public long getDurationLimitMillis();
+ method @IntRange(from=0) public long getFileSizeLimit();
+ method public android.location.Location? getLocation();
+ field public static final int DURATION_UNLIMITED = 0; // 0x0
+ field public static final int FILE_SIZE_UNLIMITED = 0; // 0x0
+ }
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class OutputResults {
+ ctor public OutputResults();
+ method public abstract android.net.Uri getOutputUri();
+ }
+
+ @RequiresApi(21) public final class PendingRecording {
+ method @SuppressCompatibility @androidx.camera.video.ExperimentalPersistentRecording public androidx.camera.video.PendingRecording asPersistentRecording();
+ method @CheckResult public androidx.camera.video.Recording start(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public androidx.camera.video.PendingRecording withAudioEnabled();
+ }
+
+ @RequiresApi(21) public class Quality {
+ field public static final androidx.camera.video.Quality FHD;
+ field public static final androidx.camera.video.Quality HD;
+ field public static final androidx.camera.video.Quality HIGHEST;
+ field public static final androidx.camera.video.Quality LOWEST;
+ field public static final androidx.camera.video.Quality SD;
+ field public static final androidx.camera.video.Quality UHD;
+ }
+
+ @RequiresApi(21) public final class QualitySelector {
+ method public static androidx.camera.video.QualitySelector from(androidx.camera.video.Quality);
+ method public static androidx.camera.video.QualitySelector from(androidx.camera.video.Quality, androidx.camera.video.FallbackStrategy);
+ method public static androidx.camera.video.QualitySelector fromOrderedList(java.util.List<androidx.camera.video.Quality!>);
+ method public static androidx.camera.video.QualitySelector fromOrderedList(java.util.List<androidx.camera.video.Quality!>, androidx.camera.video.FallbackStrategy);
+ method public static android.util.Size? getResolution(androidx.camera.core.CameraInfo, androidx.camera.video.Quality);
+ method @Deprecated public static java.util.List<androidx.camera.video.Quality!> getSupportedQualities(androidx.camera.core.CameraInfo);
+ method @Deprecated public static boolean isQualitySupported(androidx.camera.core.CameraInfo, androidx.camera.video.Quality);
+ }
+
+ @RequiresApi(21) public final class Recorder implements androidx.camera.video.VideoOutput {
+ method public int getAspectRatio();
+ method public java.util.concurrent.Executor? getExecutor();
+ method public androidx.camera.video.QualitySelector getQualitySelector();
+ method public int getTargetVideoEncodingBitRate();
+ method public static androidx.camera.video.VideoCapabilities getVideoCapabilities(androidx.camera.core.CameraInfo);
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ method @RequiresApi(26) public androidx.camera.video.PendingRecording prepareRecording(android.content.Context, androidx.camera.video.FileDescriptorOutputOptions);
+ method public androidx.camera.video.PendingRecording prepareRecording(android.content.Context, androidx.camera.video.FileOutputOptions);
+ method public androidx.camera.video.PendingRecording prepareRecording(android.content.Context, androidx.camera.video.MediaStoreOutputOptions);
+ field public static final androidx.camera.video.QualitySelector DEFAULT_QUALITY_SELECTOR;
+ }
+
+ @RequiresApi(21) public static final class Recorder.Builder {
+ ctor public Recorder.Builder();
+ method public androidx.camera.video.Recorder build();
+ method public androidx.camera.video.Recorder.Builder setAspectRatio(int);
+ method public androidx.camera.video.Recorder.Builder setExecutor(java.util.concurrent.Executor);
+ method public androidx.camera.video.Recorder.Builder setQualitySelector(androidx.camera.video.QualitySelector);
+ method public androidx.camera.video.Recorder.Builder setTargetVideoEncodingBitRate(@IntRange(from=1) int);
+ }
+
+ @RequiresApi(21) public final class Recording implements java.lang.AutoCloseable {
+ method public void close();
+ method @SuppressCompatibility @androidx.camera.video.ExperimentalPersistentRecording public boolean isPersistent();
+ method public void mute(boolean);
+ method public void pause();
+ method public void resume();
+ method public void stop();
+ }
+
+ @RequiresApi(21) @com.google.auto.value.AutoValue public abstract class RecordingStats {
+ method public abstract androidx.camera.video.AudioStats getAudioStats();
+ method public abstract long getNumBytesRecorded();
+ method public abstract long getRecordedDurationNanos();
+ }
+
+ @RequiresApi(21) public interface VideoCapabilities {
+ method public java.util.Set<androidx.camera.core.DynamicRange!> getSupportedDynamicRanges();
+ method public java.util.List<androidx.camera.video.Quality!> getSupportedQualities(androidx.camera.core.DynamicRange);
+ method public boolean isQualitySupported(androidx.camera.video.Quality, androidx.camera.core.DynamicRange);
+ }
+
+ @RequiresApi(21) public final class VideoCapture<T extends androidx.camera.video.VideoOutput> extends androidx.camera.core.UseCase {
+ method public androidx.camera.core.DynamicRange getDynamicRange();
+ method public int getMirrorMode();
+ method public T getOutput();
+ method public android.util.Range<java.lang.Integer!> getTargetFrameRate();
+ method public int getTargetRotation();
+ method public void setTargetRotation(int);
+ method public static <T extends androidx.camera.video.VideoOutput> androidx.camera.video.VideoCapture<T!> withOutput(T);
+ }
+
+ @RequiresApi(21) public static final class VideoCapture.Builder<T extends androidx.camera.video.VideoOutput> implements androidx.camera.core.ExtendableBuilder<androidx.camera.video.VideoCapture> {
+ ctor public VideoCapture.Builder(T);
+ method public androidx.camera.video.VideoCapture<T!> build();
+ method public androidx.camera.video.VideoCapture.Builder<T!> setDynamicRange(androidx.camera.core.DynamicRange);
+ method public androidx.camera.video.VideoCapture.Builder<T!> setMirrorMode(int);
+ method public androidx.camera.video.VideoCapture.Builder<T!> setTargetFrameRate(android.util.Range<java.lang.Integer!>);
+ method public androidx.camera.video.VideoCapture.Builder<T!> setTargetRotation(int);
+ }
+
+ @RequiresApi(21) public interface VideoOutput {
+ method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+ }
+
+ @RequiresApi(21) public abstract class VideoRecordEvent {
+ method public androidx.camera.video.OutputOptions getOutputOptions();
+ method public androidx.camera.video.RecordingStats getRecordingStats();
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Finalize extends androidx.camera.video.VideoRecordEvent {
+ method public Throwable? getCause();
+ method public int getError();
+ method public androidx.camera.video.OutputResults getOutputResults();
+ method public boolean hasError();
+ field public static final int ERROR_DURATION_LIMIT_REACHED = 9; // 0x9
+ field public static final int ERROR_ENCODING_FAILED = 6; // 0x6
+ field public static final int ERROR_FILE_SIZE_LIMIT_REACHED = 2; // 0x2
+ field public static final int ERROR_INSUFFICIENT_STORAGE = 3; // 0x3
+ field public static final int ERROR_INVALID_OUTPUT_OPTIONS = 5; // 0x5
+ field public static final int ERROR_NONE = 0; // 0x0
+ field public static final int ERROR_NO_VALID_DATA = 8; // 0x8
+ field public static final int ERROR_RECORDER_ERROR = 7; // 0x7
+ field public static final int ERROR_RECORDING_GARBAGE_COLLECTED = 10; // 0xa
+ field public static final int ERROR_SOURCE_INACTIVE = 4; // 0x4
+ field public static final int ERROR_UNKNOWN = 1; // 0x1
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Pause extends androidx.camera.video.VideoRecordEvent {
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Resume extends androidx.camera.video.VideoRecordEvent {
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Start extends androidx.camera.video.VideoRecordEvent {
+ }
+
+ @RequiresApi(21) public static final class VideoRecordEvent.Status extends androidx.camera.video.VideoRecordEvent {
+ }
+
+}
+
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java
index a4b0e4e4..2b78756 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/AudioSource.java
@@ -469,7 +469,7 @@
NANOSECONDS.toMicros(packetInfo.getTimestampNs()));
inputBuffer.submit();
} else {
- Logger.w(TAG, "Unable to read data from AudioRecord.");
+ Logger.w(TAG, "Unable to read data from AudioStream.");
inputBuffer.cancel();
}
sendNextAudio();
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java
index 7c3d659..bbd013b 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/audio/BufferedAudioStream.java
@@ -21,6 +21,8 @@
import static androidx.core.util.Preconditions.checkArgument;
import static androidx.core.util.Preconditions.checkState;
+import android.annotation.SuppressLint;
+
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -55,6 +57,7 @@
private static final String TAG = "BufferedAudioStream";
private static final int DEFAULT_BUFFER_SIZE_IN_FRAME = 1024;
private static final int DEFAULT_QUEUE_SIZE = 500;
+ private static final int DATA_WAITING_TIME_MILLIS = 1;
private final AtomicBoolean mIsStarted = new AtomicBoolean(false);
private final AtomicBoolean mIsReleased = new AtomicBoolean(false);
@@ -151,6 +154,7 @@
});
}
+ @SuppressLint("BanThreadSleep")
@NonNull
@Override
public PacketInfo read(@NonNull ByteBuffer byteBuffer) {
@@ -160,24 +164,40 @@
// Match collection buffer size and read buffer size to improve read efficiency.
updateCollectionBufferSizeAsync(byteBuffer.remaining());
+ // Block the thread till the audio data is actually read.
+ boolean isWaitingForData;
PacketInfo packetInfo = PacketInfo.of(0, 0);
- synchronized (mLock) {
- AudioData audioData = mAudioDataNotFullyRead;
- mAudioDataNotFullyRead = null;
- if (audioData == null) {
- audioData = mAudioDataQueue.poll();
- }
-
- if (audioData != null) {
- packetInfo = audioData.read(byteBuffer);
-
- if (audioData.getRemainingBufferSizeInBytes() > 0) {
- mAudioDataNotFullyRead = audioData;
+ do {
+ synchronized (mLock) {
+ AudioData audioData = mAudioDataNotFullyRead;
+ mAudioDataNotFullyRead = null;
+ if (audioData == null) {
+ audioData = mAudioDataQueue.poll();
}
- } else {
- Logger.d(TAG, "No data to read.");
+
+ if (audioData != null) {
+ packetInfo = audioData.read(byteBuffer);
+
+ if (audioData.getRemainingBufferSizeInBytes() > 0) {
+ mAudioDataNotFullyRead = audioData;
+ }
+ }
}
- }
+
+ // Wait for data collection if no data to read and the audio stream is still running.
+ isWaitingForData =
+ packetInfo.getSizeInBytes() <= 0 && mIsStarted.get() && !mIsReleased.get();
+
+ // Sleep to prevent busy accessing to variables.
+ if (isWaitingForData) {
+ try {
+ Thread.sleep(DATA_WAITING_TIME_MILLIS);
+ } catch (InterruptedException e) {
+ Logger.w(TAG, "Interruption while waiting for audio data", e);
+ break;
+ }
+ }
+ } while (isWaitingForData);
return packetInfo;
}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/MediaCodecInfoReportIncorrectInfoQuirk.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/MediaCodecInfoReportIncorrectInfoQuirk.java
index 735a24e..5abd8cf 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/MediaCodecInfoReportIncorrectInfoQuirk.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/compat/quirk/MediaCodecInfoReportIncorrectInfoQuirk.java
@@ -42,6 +42,8 @@
* Bug Id: 192431846, 199582287, 218841498, 203481899, 216583006, 278843124, 278855948
* Description: Quirk which denotes {@link MediaCodecInfo} queried by {@link MediaCodecList}
* returns incorrect info.
+ * <ul>
+ * <li>
* On Nokia 1, {@link CamcorderProfile} indicates it can support resolutions
* 1280x720 and 640x480 for video codec type
* {@link android.media.MediaRecorder.VideoEncoder#MPEG_4_SP}, which maps to
@@ -54,8 +56,14 @@
* "video/mp4v-es" with 1280x720 or 640x480 can be used to record video. So the
* maximum supported resolution 174x174 is probably incorrect for
* "video/mp4v-es" and doesn't make sense. See b/192431846#comment3.
+ * </li>
+ * <li>
* Motc C, X650 and LG-X230 have the same problem as Nokia 1. See b/199582287
+ * </li>
+ * <li>
* Positivo Twist 2 Pro have the same problem as Nokia 1. See b/218841498
+ * </li>
+ * <li>
* On Huawei Mate9, {@link CamcorderProfile} indicates it can support
* resolutions 3840x2160 for video codec type
* {@link android.media.MediaRecorder.VideoEncoder#HEVC}, but the current video
@@ -65,19 +73,30 @@
* unsupported resolution for 3840x2160, it only support 3840x2112. By
* experimental result, H.264 + 3840x2160 can be used to record video on this
* device. Hence use quirk to workaround this case. See b/203481899#comment2.
- * @link MediaCodecInfo} searched by {@link MediaCodecList#getCodecInfos()}
+ * </li>
+ * <li>
+ * On Redmi Note 8 Pro, {@link CamcorderProfile} indicates it can support
+ * 3840x2160, but {@link MediaCodecInfo.VideoCapabilities#isSizeSupported}
+ * returns {@code false} for 3840x2160. By experimental result, 3840x2160 can be
+ * used to record video on this device. See b/293827733.
+ * </li>
+ * <li>
+ * {@link MediaCodecInfo} searched by {@link MediaCodecList#getCodecInfos()}
* shows the maximum supported resolution of the AVC encoder is 1920x1072.
* However, the 1920x1080 option can be successfully configured properly.
- * See b/216583006, b/278843124, b/278855948.
- * Device(s): Nokia 1, Motc C, X650, LG-X230, Positivo Twist 2 Pro, Huawei Mate9, Redmi note 4
- * , LG K10 LTE K430, Samsung Galaxy A03 Core, Vivo Y75, Realme C11 2021
+ * See b/216583006, b/278843124, b/278855948, b/293827733.
+ * </li>
+ * </ul>
+ * Device(s): Nokia 1, Motc C, X650, LG-X230, Positivo Twist 2 Pro, Huawei Mate9,
+ * Redmi Note 8 Pro, Redmi Note 4, Redmi Note 9, LG K10 LTE K430,
+ * Samsung Galaxy A03 Core, Vivo Y75, Realme C11 2021
*/
@RequiresApi(21) // TODO(b/200306659): Remove and replace with annotation on package-info.java
public class MediaCodecInfoReportIncorrectInfoQuirk implements Quirk {
static boolean load() {
return isNokia1() || isMotoC() || isX650() || isX230() || isHuaweiMate9()
- || isPositivoTwist2Pro() || isFHDProblematicDevice();
+ || isRedmiNote8Pro() || isPositivoTwist2Pro() || isFHDProblematicDevice();
}
private static boolean isNokia1() {
@@ -101,6 +120,11 @@
return "Huawei".equalsIgnoreCase(Build.BRAND) && "mha-l29".equalsIgnoreCase(Build.MODEL);
}
+ private static boolean isRedmiNote8Pro() {
+ return "Redmi".equalsIgnoreCase(Build.BRAND) && "Redmi Note 8 Pro".equalsIgnoreCase(
+ Build.MODEL);
+ }
+
private static boolean isPositivoTwist2Pro() {
return "positivo".equalsIgnoreCase(Build.BRAND) && "twist 2 pro".equalsIgnoreCase(
Build.MODEL);
@@ -109,6 +133,7 @@
public static final List<String> INCORRECT_FHD_PROFILE_MODEL_LIST = Arrays.asList(
"lg-k430",
"redmi note 4",
+ "m2003j15sc", // Redmi Note 9
"rmx3231",
"v2117",
"sm-a032f",
@@ -121,7 +146,7 @@
MediaFormatResolver formatResolver = new MediaFormatResolver(mediaFormat);
if (isNokia1() || isMotoC() || isX650() || isX230() || isPositivoTwist2Pro()) {
return formatResolver.isMpeg4();
- } else if (isHuaweiMate9()) {
+ } else if (isHuaweiMate9() || isRedmiNote8Pro()) {
return formatResolver.isVideo() && formatResolver.isSize(3840, 2160);
} else if (isFHDProblematicDevice()) {
return formatResolver.isAvc() && formatResolver.isSize(1920, 1080);
diff --git a/camera/camera-view/api/1.3.0-beta03.txt b/camera/camera-view/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..6184aeb
--- /dev/null
+++ b/camera/camera-view/api/1.3.0-beta03.txt
@@ -0,0 +1,173 @@
+// Signature format: 4.0
+package androidx.camera.view {
+
+ @RequiresApi(21) public abstract class CameraController {
+ method @MainThread public void clearEffects();
+ method @MainThread public void clearImageAnalysisAnalyzer();
+ method @MainThread public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method @MainThread public androidx.camera.core.CameraControl? getCameraControl();
+ method @MainThread public androidx.camera.core.CameraInfo? getCameraInfo();
+ method @MainThread public androidx.camera.core.CameraSelector getCameraSelector();
+ method @MainThread public java.util.concurrent.Executor? getImageAnalysisBackgroundExecutor();
+ method @MainThread public int getImageAnalysisBackpressureStrategy();
+ method @MainThread public int getImageAnalysisImageQueueDepth();
+ method @MainThread public androidx.camera.view.CameraController.OutputSize? getImageAnalysisTargetSize();
+ method @MainThread public int getImageCaptureFlashMode();
+ method @MainThread public java.util.concurrent.Executor? getImageCaptureIoExecutor();
+ method @MainThread public int getImageCaptureMode();
+ method @MainThread public androidx.camera.view.CameraController.OutputSize? getImageCaptureTargetSize();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> getInitializationFuture();
+ method @MainThread public androidx.camera.view.CameraController.OutputSize? getPreviewTargetSize();
+ method @MainThread public androidx.lifecycle.LiveData<java.lang.Integer!> getTapToFocusState();
+ method @MainThread public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method @MainThread public androidx.camera.video.QualitySelector getVideoCaptureQualitySelector();
+ method @MainThread public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+ method @MainThread public boolean hasCamera(androidx.camera.core.CameraSelector);
+ method @MainThread public boolean isImageAnalysisEnabled();
+ method @MainThread public boolean isImageCaptureEnabled();
+ method @MainThread public boolean isPinchToZoomEnabled();
+ method @MainThread public boolean isRecording();
+ method @MainThread public boolean isTapToFocusEnabled();
+ method @MainThread public boolean isVideoCaptureEnabled();
+ method @MainThread public void setCameraSelector(androidx.camera.core.CameraSelector);
+ method @MainThread public void setEffects(java.util.Set<androidx.camera.core.CameraEffect!>);
+ method @MainThread public void setEnabledUseCases(int);
+ method @MainThread public void setImageAnalysisAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method @MainThread public void setImageAnalysisBackgroundExecutor(java.util.concurrent.Executor?);
+ method @MainThread public void setImageAnalysisBackpressureStrategy(int);
+ method @MainThread public void setImageAnalysisImageQueueDepth(int);
+ method @MainThread public void setImageAnalysisTargetSize(androidx.camera.view.CameraController.OutputSize?);
+ method @MainThread public void setImageCaptureFlashMode(int);
+ method @MainThread public void setImageCaptureIoExecutor(java.util.concurrent.Executor?);
+ method @MainThread public void setImageCaptureMode(int);
+ method @MainThread public void setImageCaptureTargetSize(androidx.camera.view.CameraController.OutputSize?);
+ method @MainThread public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method @MainThread public void setPinchToZoomEnabled(boolean);
+ method @MainThread public void setPreviewTargetSize(androidx.camera.view.CameraController.OutputSize?);
+ method @MainThread public void setTapToFocusEnabled(boolean);
+ method @MainThread public void setVideoCaptureQualitySelector(androidx.camera.video.QualitySelector);
+ method @MainThread public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method @MainThread @RequiresApi(26) public androidx.camera.video.Recording startRecording(androidx.camera.video.FileDescriptorOutputOptions, androidx.camera.view.video.AudioConfig, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @MainThread public androidx.camera.video.Recording startRecording(androidx.camera.video.FileOutputOptions, androidx.camera.view.video.AudioConfig, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @MainThread public androidx.camera.video.Recording startRecording(androidx.camera.video.MediaStoreOutputOptions, androidx.camera.view.video.AudioConfig, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @MainThread public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method @MainThread public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ field public static final int COORDINATE_SYSTEM_VIEW_REFERENCED = 1; // 0x1
+ field public static final int IMAGE_ANALYSIS = 2; // 0x2
+ field public static final int IMAGE_CAPTURE = 1; // 0x1
+ field public static final int TAP_TO_FOCUS_FAILED = 4; // 0x4
+ field public static final int TAP_TO_FOCUS_FOCUSED = 2; // 0x2
+ field public static final int TAP_TO_FOCUS_NOT_FOCUSED = 3; // 0x3
+ field public static final int TAP_TO_FOCUS_NOT_STARTED = 0; // 0x0
+ field public static final int TAP_TO_FOCUS_STARTED = 1; // 0x1
+ field public static final int VIDEO_CAPTURE = 4; // 0x4
+ }
+
+ @RequiresApi(21) public static final class CameraController.OutputSize {
+ ctor public CameraController.OutputSize(android.util.Size);
+ ctor public CameraController.OutputSize(int);
+ method public int getAspectRatio();
+ method public android.util.Size? getResolution();
+ field public static final int UNASSIGNED_ASPECT_RATIO = -1; // 0xffffffff
+ }
+
+ @RequiresApi(21) public final class LifecycleCameraController extends androidx.camera.view.CameraController {
+ ctor public LifecycleCameraController(android.content.Context);
+ method @MainThread public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
+ method @MainThread public void unbind();
+ }
+
+ @RequiresApi(21) public final class PreviewView extends android.widget.FrameLayout {
+ ctor @UiThread public PreviewView(android.content.Context);
+ ctor @UiThread public PreviewView(android.content.Context, android.util.AttributeSet?);
+ ctor @UiThread public PreviewView(android.content.Context, android.util.AttributeSet?, int);
+ ctor @UiThread public PreviewView(android.content.Context, android.util.AttributeSet?, int, int);
+ method @UiThread public android.graphics.Bitmap? getBitmap();
+ method @UiThread public androidx.camera.view.CameraController? getController();
+ method @UiThread public androidx.camera.view.PreviewView.ImplementationMode getImplementationMode();
+ method @UiThread public androidx.camera.core.MeteringPointFactory getMeteringPointFactory();
+ method @SuppressCompatibility public androidx.camera.view.transform.OutputTransform? getOutputTransform();
+ method public androidx.lifecycle.LiveData<androidx.camera.view.PreviewView.StreamState!> getPreviewStreamState();
+ method @UiThread public androidx.camera.view.PreviewView.ScaleType getScaleType();
+ method @UiThread public androidx.camera.core.Preview.SurfaceProvider getSurfaceProvider();
+ method @UiThread public androidx.camera.core.ViewPort? getViewPort();
+ method @UiThread public androidx.camera.core.ViewPort? getViewPort(int);
+ method @UiThread public void setController(androidx.camera.view.CameraController?);
+ method @UiThread public void setImplementationMode(androidx.camera.view.PreviewView.ImplementationMode);
+ method @UiThread public void setScaleType(androidx.camera.view.PreviewView.ScaleType);
+ }
+
+ @RequiresApi(21) public enum PreviewView.ImplementationMode {
+ enum_constant public static final androidx.camera.view.PreviewView.ImplementationMode COMPATIBLE;
+ enum_constant public static final androidx.camera.view.PreviewView.ImplementationMode PERFORMANCE;
+ }
+
+ @RequiresApi(21) public enum PreviewView.ScaleType {
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FILL_CENTER;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FILL_END;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FILL_START;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FIT_CENTER;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FIT_END;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FIT_START;
+ }
+
+ public enum PreviewView.StreamState {
+ enum_constant public static final androidx.camera.view.PreviewView.StreamState IDLE;
+ enum_constant public static final androidx.camera.view.PreviewView.StreamState STREAMING;
+ }
+
+ @RequiresApi(21) public final class RotationProvider {
+ ctor public RotationProvider(android.content.Context);
+ method @CheckResult public boolean addListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method public void removeListener(androidx.camera.view.RotationProvider.Listener);
+ }
+
+ public static interface RotationProvider.Listener {
+ method public void onRotationChanged(int);
+ }
+
+}
+
+package androidx.camera.view.transform {
+
+ @SuppressCompatibility @RequiresApi(21) public final class CoordinateTransform {
+ ctor public CoordinateTransform(androidx.camera.view.transform.OutputTransform, androidx.camera.view.transform.OutputTransform);
+ method public void mapPoint(android.graphics.PointF);
+ method public void mapPoints(float[]);
+ method public void mapRect(android.graphics.RectF);
+ method public void transform(android.graphics.Matrix);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) public final class FileTransformFactory {
+ ctor public FileTransformFactory();
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(android.content.ContentResolver, android.net.Uri) throws java.io.IOException;
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(java.io.File) throws java.io.IOException;
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(java.io.InputStream) throws java.io.IOException;
+ method public boolean isUsingExifOrientation();
+ method public void setUsingExifOrientation(boolean);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) public final class ImageProxyTransformFactory {
+ ctor public ImageProxyTransformFactory();
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(androidx.camera.core.ImageProxy);
+ method public boolean isUsingCropRect();
+ method public boolean isUsingRotationDegrees();
+ method public void setUsingCropRect(boolean);
+ method public void setUsingRotationDegrees(boolean);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) public final class OutputTransform {
+ }
+
+}
+
+package androidx.camera.view.video {
+
+ @RequiresApi(21) public class AudioConfig {
+ method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public static androidx.camera.view.video.AudioConfig create(boolean);
+ method public boolean getAudioEnabled();
+ field public static final androidx.camera.view.video.AudioConfig AUDIO_DISABLED;
+ }
+
+}
+
diff --git a/camera/camera-view/api/res-1.3.0-beta03.txt b/camera/camera-view/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-view/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-view/api/restricted_1.3.0-beta03.txt b/camera/camera-view/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..6184aeb
--- /dev/null
+++ b/camera/camera-view/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,173 @@
+// Signature format: 4.0
+package androidx.camera.view {
+
+ @RequiresApi(21) public abstract class CameraController {
+ method @MainThread public void clearEffects();
+ method @MainThread public void clearImageAnalysisAnalyzer();
+ method @MainThread public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+ method @MainThread public androidx.camera.core.CameraControl? getCameraControl();
+ method @MainThread public androidx.camera.core.CameraInfo? getCameraInfo();
+ method @MainThread public androidx.camera.core.CameraSelector getCameraSelector();
+ method @MainThread public java.util.concurrent.Executor? getImageAnalysisBackgroundExecutor();
+ method @MainThread public int getImageAnalysisBackpressureStrategy();
+ method @MainThread public int getImageAnalysisImageQueueDepth();
+ method @MainThread public androidx.camera.view.CameraController.OutputSize? getImageAnalysisTargetSize();
+ method @MainThread public int getImageCaptureFlashMode();
+ method @MainThread public java.util.concurrent.Executor? getImageCaptureIoExecutor();
+ method @MainThread public int getImageCaptureMode();
+ method @MainThread public androidx.camera.view.CameraController.OutputSize? getImageCaptureTargetSize();
+ method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> getInitializationFuture();
+ method @MainThread public androidx.camera.view.CameraController.OutputSize? getPreviewTargetSize();
+ method @MainThread public androidx.lifecycle.LiveData<java.lang.Integer!> getTapToFocusState();
+ method @MainThread public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+ method @MainThread public androidx.camera.video.QualitySelector getVideoCaptureQualitySelector();
+ method @MainThread public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+ method @MainThread public boolean hasCamera(androidx.camera.core.CameraSelector);
+ method @MainThread public boolean isImageAnalysisEnabled();
+ method @MainThread public boolean isImageCaptureEnabled();
+ method @MainThread public boolean isPinchToZoomEnabled();
+ method @MainThread public boolean isRecording();
+ method @MainThread public boolean isTapToFocusEnabled();
+ method @MainThread public boolean isVideoCaptureEnabled();
+ method @MainThread public void setCameraSelector(androidx.camera.core.CameraSelector);
+ method @MainThread public void setEffects(java.util.Set<androidx.camera.core.CameraEffect!>);
+ method @MainThread public void setEnabledUseCases(int);
+ method @MainThread public void setImageAnalysisAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+ method @MainThread public void setImageAnalysisBackgroundExecutor(java.util.concurrent.Executor?);
+ method @MainThread public void setImageAnalysisBackpressureStrategy(int);
+ method @MainThread public void setImageAnalysisImageQueueDepth(int);
+ method @MainThread public void setImageAnalysisTargetSize(androidx.camera.view.CameraController.OutputSize?);
+ method @MainThread public void setImageCaptureFlashMode(int);
+ method @MainThread public void setImageCaptureIoExecutor(java.util.concurrent.Executor?);
+ method @MainThread public void setImageCaptureMode(int);
+ method @MainThread public void setImageCaptureTargetSize(androidx.camera.view.CameraController.OutputSize?);
+ method @MainThread public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+ method @MainThread public void setPinchToZoomEnabled(boolean);
+ method @MainThread public void setPreviewTargetSize(androidx.camera.view.CameraController.OutputSize?);
+ method @MainThread public void setTapToFocusEnabled(boolean);
+ method @MainThread public void setVideoCaptureQualitySelector(androidx.camera.video.QualitySelector);
+ method @MainThread public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+ method @MainThread @RequiresApi(26) public androidx.camera.video.Recording startRecording(androidx.camera.video.FileDescriptorOutputOptions, androidx.camera.view.video.AudioConfig, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @MainThread public androidx.camera.video.Recording startRecording(androidx.camera.video.FileOutputOptions, androidx.camera.view.video.AudioConfig, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @MainThread public androidx.camera.video.Recording startRecording(androidx.camera.video.MediaStoreOutputOptions, androidx.camera.view.video.AudioConfig, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.video.VideoRecordEvent!>);
+ method @MainThread public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+ method @MainThread public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+ field public static final int COORDINATE_SYSTEM_VIEW_REFERENCED = 1; // 0x1
+ field public static final int IMAGE_ANALYSIS = 2; // 0x2
+ field public static final int IMAGE_CAPTURE = 1; // 0x1
+ field public static final int TAP_TO_FOCUS_FAILED = 4; // 0x4
+ field public static final int TAP_TO_FOCUS_FOCUSED = 2; // 0x2
+ field public static final int TAP_TO_FOCUS_NOT_FOCUSED = 3; // 0x3
+ field public static final int TAP_TO_FOCUS_NOT_STARTED = 0; // 0x0
+ field public static final int TAP_TO_FOCUS_STARTED = 1; // 0x1
+ field public static final int VIDEO_CAPTURE = 4; // 0x4
+ }
+
+ @RequiresApi(21) public static final class CameraController.OutputSize {
+ ctor public CameraController.OutputSize(android.util.Size);
+ ctor public CameraController.OutputSize(int);
+ method public int getAspectRatio();
+ method public android.util.Size? getResolution();
+ field public static final int UNASSIGNED_ASPECT_RATIO = -1; // 0xffffffff
+ }
+
+ @RequiresApi(21) public final class LifecycleCameraController extends androidx.camera.view.CameraController {
+ ctor public LifecycleCameraController(android.content.Context);
+ method @MainThread public void bindToLifecycle(androidx.lifecycle.LifecycleOwner);
+ method @MainThread public void unbind();
+ }
+
+ @RequiresApi(21) public final class PreviewView extends android.widget.FrameLayout {
+ ctor @UiThread public PreviewView(android.content.Context);
+ ctor @UiThread public PreviewView(android.content.Context, android.util.AttributeSet?);
+ ctor @UiThread public PreviewView(android.content.Context, android.util.AttributeSet?, int);
+ ctor @UiThread public PreviewView(android.content.Context, android.util.AttributeSet?, int, int);
+ method @UiThread public android.graphics.Bitmap? getBitmap();
+ method @UiThread public androidx.camera.view.CameraController? getController();
+ method @UiThread public androidx.camera.view.PreviewView.ImplementationMode getImplementationMode();
+ method @UiThread public androidx.camera.core.MeteringPointFactory getMeteringPointFactory();
+ method @SuppressCompatibility public androidx.camera.view.transform.OutputTransform? getOutputTransform();
+ method public androidx.lifecycle.LiveData<androidx.camera.view.PreviewView.StreamState!> getPreviewStreamState();
+ method @UiThread public androidx.camera.view.PreviewView.ScaleType getScaleType();
+ method @UiThread public androidx.camera.core.Preview.SurfaceProvider getSurfaceProvider();
+ method @UiThread public androidx.camera.core.ViewPort? getViewPort();
+ method @UiThread public androidx.camera.core.ViewPort? getViewPort(int);
+ method @UiThread public void setController(androidx.camera.view.CameraController?);
+ method @UiThread public void setImplementationMode(androidx.camera.view.PreviewView.ImplementationMode);
+ method @UiThread public void setScaleType(androidx.camera.view.PreviewView.ScaleType);
+ }
+
+ @RequiresApi(21) public enum PreviewView.ImplementationMode {
+ enum_constant public static final androidx.camera.view.PreviewView.ImplementationMode COMPATIBLE;
+ enum_constant public static final androidx.camera.view.PreviewView.ImplementationMode PERFORMANCE;
+ }
+
+ @RequiresApi(21) public enum PreviewView.ScaleType {
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FILL_CENTER;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FILL_END;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FILL_START;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FIT_CENTER;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FIT_END;
+ enum_constant public static final androidx.camera.view.PreviewView.ScaleType FIT_START;
+ }
+
+ public enum PreviewView.StreamState {
+ enum_constant public static final androidx.camera.view.PreviewView.StreamState IDLE;
+ enum_constant public static final androidx.camera.view.PreviewView.StreamState STREAMING;
+ }
+
+ @RequiresApi(21) public final class RotationProvider {
+ ctor public RotationProvider(android.content.Context);
+ method @CheckResult public boolean addListener(java.util.concurrent.Executor, androidx.camera.view.RotationProvider.Listener);
+ method public void removeListener(androidx.camera.view.RotationProvider.Listener);
+ }
+
+ public static interface RotationProvider.Listener {
+ method public void onRotationChanged(int);
+ }
+
+}
+
+package androidx.camera.view.transform {
+
+ @SuppressCompatibility @RequiresApi(21) public final class CoordinateTransform {
+ ctor public CoordinateTransform(androidx.camera.view.transform.OutputTransform, androidx.camera.view.transform.OutputTransform);
+ method public void mapPoint(android.graphics.PointF);
+ method public void mapPoints(float[]);
+ method public void mapRect(android.graphics.RectF);
+ method public void transform(android.graphics.Matrix);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) public final class FileTransformFactory {
+ ctor public FileTransformFactory();
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(android.content.ContentResolver, android.net.Uri) throws java.io.IOException;
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(java.io.File) throws java.io.IOException;
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(java.io.InputStream) throws java.io.IOException;
+ method public boolean isUsingExifOrientation();
+ method public void setUsingExifOrientation(boolean);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) public final class ImageProxyTransformFactory {
+ ctor public ImageProxyTransformFactory();
+ method public androidx.camera.view.transform.OutputTransform getOutputTransform(androidx.camera.core.ImageProxy);
+ method public boolean isUsingCropRect();
+ method public boolean isUsingRotationDegrees();
+ method public void setUsingCropRect(boolean);
+ method public void setUsingRotationDegrees(boolean);
+ }
+
+ @SuppressCompatibility @RequiresApi(21) public final class OutputTransform {
+ }
+
+}
+
+package androidx.camera.view.video {
+
+ @RequiresApi(21) public class AudioConfig {
+ method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public static androidx.camera.view.video.AudioConfig create(boolean);
+ method public boolean getAudioEnabled();
+ field public static final androidx.camera.view.video.AudioConfig AUDIO_DISABLED;
+ }
+
+}
+
diff --git a/camera/camera-viewfinder-compose/api/1.3.0-beta03.txt b/camera/camera-viewfinder-compose/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-viewfinder-compose/api/1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-viewfinder-compose/api/res-1.3.0-beta03.txt b/camera/camera-viewfinder-compose/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-viewfinder-compose/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-viewfinder-compose/api/restricted_1.3.0-beta03.txt b/camera/camera-viewfinder-compose/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-viewfinder-compose/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-viewfinder-core/api/1.3.0-beta03.txt b/camera/camera-viewfinder-core/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-viewfinder-core/api/1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-viewfinder-core/api/res-1.3.0-beta03.txt b/camera/camera-viewfinder-core/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-viewfinder-core/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-viewfinder-core/api/restricted_1.3.0-beta03.txt b/camera/camera-viewfinder-core/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/camera/camera-viewfinder-core/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/camera/camera-viewfinder/api/1.3.0-beta03.txt b/camera/camera-viewfinder/api/1.3.0-beta03.txt
new file mode 100644
index 0000000..a7333d7
--- /dev/null
+++ b/camera/camera-viewfinder/api/1.3.0-beta03.txt
@@ -0,0 +1,58 @@
+// Signature format: 4.0
+package androidx.camera.viewfinder {
+
+ @RequiresApi(21) public final class CameraViewfinder extends android.widget.FrameLayout {
+ ctor @UiThread public CameraViewfinder(android.content.Context);
+ ctor @UiThread public CameraViewfinder(android.content.Context, android.util.AttributeSet?);
+ ctor @UiThread public CameraViewfinder(android.content.Context, android.util.AttributeSet?, int);
+ ctor @UiThread public CameraViewfinder(android.content.Context, android.util.AttributeSet?, int, int);
+ method @UiThread public android.graphics.Bitmap? getBitmap();
+ method @UiThread public androidx.camera.viewfinder.CameraViewfinder.ImplementationMode getImplementationMode();
+ method @UiThread public androidx.camera.viewfinder.CameraViewfinder.ScaleType getScaleType();
+ method @UiThread public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> requestSurfaceAsync(androidx.camera.viewfinder.ViewfinderSurfaceRequest);
+ method @UiThread public void setScaleType(androidx.camera.viewfinder.CameraViewfinder.ScaleType);
+ }
+
+ @RequiresApi(21) public enum CameraViewfinder.ImplementationMode {
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ImplementationMode COMPATIBLE;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ImplementationMode PERFORMANCE;
+ }
+
+ @RequiresApi(21) public enum CameraViewfinder.ScaleType {
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FILL_CENTER;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FILL_END;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FILL_START;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FIT_CENTER;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FIT_END;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FIT_START;
+ }
+
+ @RequiresApi(21) public final class CameraViewfinderExt {
+ method public suspend Object? requestSurface(androidx.camera.viewfinder.CameraViewfinder, androidx.camera.viewfinder.ViewfinderSurfaceRequest viewfinderSurfaceRequest, kotlin.coroutines.Continuation<? super android.view.Surface>);
+ field public static final androidx.camera.viewfinder.CameraViewfinderExt INSTANCE;
+ }
+
+ @RequiresApi(21) public class ViewfinderSurfaceRequest {
+ method public androidx.camera.viewfinder.CameraViewfinder.ImplementationMode? getImplementationMode();
+ method public int getLensFacing();
+ method public android.util.Size getResolution();
+ method public int getSensorOrientation();
+ method public void markSurfaceSafeToRelease();
+ }
+
+ public static final class ViewfinderSurfaceRequest.Builder {
+ ctor public ViewfinderSurfaceRequest.Builder(android.util.Size);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.ViewfinderSurfaceRequest);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder);
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest build();
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder setImplementationMode(androidx.camera.viewfinder.CameraViewfinder.ImplementationMode?);
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder setLensFacing(int);
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder setSensorOrientation(int);
+ }
+
+ public final class ViewfinderSurfaceRequestUtil {
+ method @RequiresApi(21) public static androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder populateFromCharacteristics(androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder, android.hardware.camera2.CameraCharacteristics cameraCharacteristics);
+ }
+
+}
+
diff --git a/camera/camera-viewfinder/api/res-1.3.0-beta03.txt b/camera/camera-viewfinder/api/res-1.3.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-viewfinder/api/res-1.3.0-beta03.txt
diff --git a/camera/camera-viewfinder/api/restricted_1.3.0-beta03.txt b/camera/camera-viewfinder/api/restricted_1.3.0-beta03.txt
new file mode 100644
index 0000000..a7333d7
--- /dev/null
+++ b/camera/camera-viewfinder/api/restricted_1.3.0-beta03.txt
@@ -0,0 +1,58 @@
+// Signature format: 4.0
+package androidx.camera.viewfinder {
+
+ @RequiresApi(21) public final class CameraViewfinder extends android.widget.FrameLayout {
+ ctor @UiThread public CameraViewfinder(android.content.Context);
+ ctor @UiThread public CameraViewfinder(android.content.Context, android.util.AttributeSet?);
+ ctor @UiThread public CameraViewfinder(android.content.Context, android.util.AttributeSet?, int);
+ ctor @UiThread public CameraViewfinder(android.content.Context, android.util.AttributeSet?, int, int);
+ method @UiThread public android.graphics.Bitmap? getBitmap();
+ method @UiThread public androidx.camera.viewfinder.CameraViewfinder.ImplementationMode getImplementationMode();
+ method @UiThread public androidx.camera.viewfinder.CameraViewfinder.ScaleType getScaleType();
+ method @UiThread public com.google.common.util.concurrent.ListenableFuture<android.view.Surface!> requestSurfaceAsync(androidx.camera.viewfinder.ViewfinderSurfaceRequest);
+ method @UiThread public void setScaleType(androidx.camera.viewfinder.CameraViewfinder.ScaleType);
+ }
+
+ @RequiresApi(21) public enum CameraViewfinder.ImplementationMode {
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ImplementationMode COMPATIBLE;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ImplementationMode PERFORMANCE;
+ }
+
+ @RequiresApi(21) public enum CameraViewfinder.ScaleType {
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FILL_CENTER;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FILL_END;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FILL_START;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FIT_CENTER;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FIT_END;
+ enum_constant public static final androidx.camera.viewfinder.CameraViewfinder.ScaleType FIT_START;
+ }
+
+ @RequiresApi(21) public final class CameraViewfinderExt {
+ method public suspend Object? requestSurface(androidx.camera.viewfinder.CameraViewfinder, androidx.camera.viewfinder.ViewfinderSurfaceRequest viewfinderSurfaceRequest, kotlin.coroutines.Continuation<? super android.view.Surface>);
+ field public static final androidx.camera.viewfinder.CameraViewfinderExt INSTANCE;
+ }
+
+ @RequiresApi(21) public class ViewfinderSurfaceRequest {
+ method public androidx.camera.viewfinder.CameraViewfinder.ImplementationMode? getImplementationMode();
+ method public int getLensFacing();
+ method public android.util.Size getResolution();
+ method public int getSensorOrientation();
+ method public void markSurfaceSafeToRelease();
+ }
+
+ public static final class ViewfinderSurfaceRequest.Builder {
+ ctor public ViewfinderSurfaceRequest.Builder(android.util.Size);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.ViewfinderSurfaceRequest);
+ ctor public ViewfinderSurfaceRequest.Builder(androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder);
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest build();
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder setImplementationMode(androidx.camera.viewfinder.CameraViewfinder.ImplementationMode?);
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder setLensFacing(int);
+ method public androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder setSensorOrientation(int);
+ }
+
+ public final class ViewfinderSurfaceRequestUtil {
+ method @RequiresApi(21) public static androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder populateFromCharacteristics(androidx.camera.viewfinder.ViewfinderSurfaceRequest.Builder, android.hardware.camera2.CameraCharacteristics cameraCharacteristics);
+ }
+
+}
+
diff --git a/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml b/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
index 5e483e9..425ca58 100644
--- a/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
+++ b/camera/integration-tests/coretestapp/src/main/AndroidManifest.xml
@@ -65,6 +65,17 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity
+ android:name=".VideoCameraSwitchingActivity"
+ android:exported="true"
+ android:label="Video Camera Switching Test App"
+ android:taskAffinity="androidx.camera.integration.core.VideoCameraSwitchingActivity"
+ android:theme="@style/NoTitleTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
<uses-feature android:glEsVersion="0x00020000" />
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java
new file mode 100644
index 0000000..13c9cbd
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/VideoCameraSwitchingActivity.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.camera.integration.core;
+
+import android.annotation.SuppressLint;
+import android.content.ContentValues;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.camera.core.Camera;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.Logger;
+import androidx.camera.core.Preview;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.camera.video.ExperimentalPersistentRecording;
+import androidx.camera.video.FileOutputOptions;
+import androidx.camera.video.MediaStoreOutputOptions;
+import androidx.camera.video.PendingRecording;
+import androidx.camera.video.Recorder;
+import androidx.camera.video.Recording;
+import androidx.camera.video.VideoCapture;
+import androidx.camera.video.VideoRecordEvent;
+import androidx.camera.video.internal.compat.quirk.DeviceQuirks;
+import androidx.camera.video.internal.compat.quirk.MediaStoreVideoCannotWrite;
+import androidx.camera.view.PreviewView;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+import androidx.core.util.Preconditions;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.File;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Activity for verifying behavior of switching camera during a recording.
+ */
+public class VideoCameraSwitchingActivity extends AppCompatActivity {
+
+ private static final String TAG = "VideoCameraSwitchingActivity";
+ // Possible values for this intent key: "BACKWARD" or "FORWARD".
+ private static final String INTENT_EXTRA_CAMERA_DIRECTION = "camera_direction";
+ // Launch the activity with the specified recording duration.
+ private static final String INTENT_EXTRA_DURATION = "recording_duration";
+ // Launch the activity with the specified camera switching time.
+ private static final String INTENT_EXTRA_SWITCH_TIME = "recording_switch_time";
+ private static final long INVALID_TIME_VALUE = -1;
+ private static final int REQUEST_CODE_PERMISSIONS = 1001;
+ private static final String[] REQUIRED_PERMISSIONS = new String[] {
+ "android.permission.CAMERA"
+ };
+ private static final long DEFAULT_DURATION_MILLIS = 10000;
+ private static final long DEFAULT_SWITCH_TIME_MILLIS = 5000;
+
+ @NonNull
+ private CameraSelector mCameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
+ @Nullable
+ private ProcessCameraProvider mCameraProvider;
+ @Nullable
+ private PreviewView mPreviewView;
+ @Nullable
+ private EditText mDurationText;
+ @Nullable
+ private EditText mSwitchTimeText;
+ @Nullable
+ private Button mStartButton;
+ @Nullable
+ private Preview mPreview;
+ @Nullable
+ private VideoCapture<Recorder> mVideoCapture;
+ @Nullable
+ private Camera mCamera;
+ @Nullable
+ private Recording mRecording;
+ private boolean mNotYetSwitched = true;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_video_camera_switching);
+
+ Bundle bundle = this.getIntent().getExtras();
+ long extraDurationMillis = INVALID_TIME_VALUE;
+ long extraSwitchTimeMillis = INVALID_TIME_VALUE;
+ if (bundle != null) {
+ String extraCameraDirection = bundle.getString(INTENT_EXTRA_CAMERA_DIRECTION);
+ if (extraCameraDirection != null) {
+ if (extraCameraDirection.equals("FORWARD")) {
+ mCameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA;
+ } else {
+ mCameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
+ }
+ }
+ extraDurationMillis = bundle.getLong(INTENT_EXTRA_DURATION, INVALID_TIME_VALUE);
+ extraSwitchTimeMillis = bundle.getLong(INTENT_EXTRA_SWITCH_TIME, INVALID_TIME_VALUE);
+ }
+
+ mPreviewView = findViewById(R.id.camera_preview);
+ mDurationText = findViewById(R.id.duration);
+ mSwitchTimeText = findViewById(R.id.switch_time);
+ mStartButton = findViewById(R.id.start_recording);
+
+ Preconditions.checkNotNull(mPreviewView, "Cannot get the preview view.");
+ Preconditions.checkNotNull(mDurationText, "Cannot get the duration text view.");
+ Preconditions.checkNotNull(mSwitchTimeText, "Cannot get the switch time text view.");
+ Preconditions.checkNotNull(mStartButton, "Cannot get the start button view.");
+
+ mDurationText.setText(Long.toString(
+ extraDurationMillis == INVALID_TIME_VALUE ? DEFAULT_DURATION_MILLIS
+ : extraDurationMillis));
+ mSwitchTimeText.setText(Long.toString(
+ extraSwitchTimeMillis == INVALID_TIME_VALUE ? DEFAULT_SWITCH_TIME_MILLIS
+ : extraSwitchTimeMillis));
+ mStartButton.setOnClickListener(view -> startRecording());
+
+ if (allPermissionsGranted()) {
+ if (mCameraProvider != null) {
+ mCameraProvider.unbindAll();
+ }
+ prepareCamera();
+ } else {
+ ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
+ }
+ }
+
+ private void prepareCamera() {
+ final ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
+ ProcessCameraProvider.getInstance(this);
+ cameraProviderFuture.addListener(() -> {
+ try {
+ mCameraProvider = cameraProviderFuture.get();
+ bindUseCases(mCameraProvider);
+ } catch (ExecutionException | InterruptedException e) {
+ String msg = "Fail to bind the use cases with the camera.";
+ Logger.d(TAG, msg);
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+ }
+ }, ContextCompat.getMainExecutor(this));
+ }
+
+ private void bindUseCases(@NonNull ProcessCameraProvider cameraProvider) {
+ cameraProvider.unbindAll();
+ mPreviewView.setImplementationMode(PreviewView.ImplementationMode.COMPATIBLE);
+ mPreview = new Preview.Builder().build();
+ mPreview.setSurfaceProvider(mPreviewView.getSurfaceProvider());
+ mVideoCapture = VideoCapture.withOutput(new Recorder.Builder().build());
+ mCamera = cameraProvider.bindToLifecycle(this, mCameraSelector, mPreview, mVideoCapture);
+ }
+
+ private void switchCamera() {
+ Preconditions.checkNotNull(mCamera, "The camera instance should not be null.");
+ Preconditions.checkNotNull(mCameraProvider, "The camera provider should not be null");
+ Preconditions.checkNotNull(mPreview, "The preview use case should not be null.");
+ Preconditions.checkNotNull(mVideoCapture, "The video capture use case should not be null.");
+ mCameraProvider.unbindAll();
+ final CameraSelector newLensFacing;
+ switch (mCamera.getCameraInfo().getLensFacing()) {
+ case CameraSelector.LENS_FACING_BACK:
+ newLensFacing = CameraSelector.DEFAULT_FRONT_CAMERA;
+ break;
+ case CameraSelector.LENS_FACING_FRONT:
+ newLensFacing = CameraSelector.DEFAULT_BACK_CAMERA;
+ break;
+ default:
+ throw new IllegalStateException("Invalid camera lens facing.");
+ }
+ mCamera = mCameraProvider.bindToLifecycle(this, newLensFacing, mPreview, mVideoCapture);
+ }
+
+ @SuppressLint("NullAnnotationGroup")
+ @SuppressWarnings("FutureReturnValueIgnored")
+ @OptIn(markerClass = ExperimentalPersistentRecording.class)
+ private void startRecording() {
+ Preconditions.checkNotNull(mVideoCapture, "The video capture use case should not be null.");
+ final long expectedDurationMillis = Long.parseLong(mDurationText.getText().toString());
+ final long expectedSwitchTimeMillis = Long.parseLong(mSwitchTimeText.getText().toString());
+ if (expectedSwitchTimeMillis >= expectedDurationMillis) {
+ String msg = "The switch time should be less than the duration.";
+ Logger.d(TAG, msg);
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ mStartButton.setClickable(false);
+ mStartButton.setText(R.string.record_button_recording);
+ mDurationText.setClickable(false);
+ mSwitchTimeText.setClickable(false);
+
+ final PendingRecording pendingRecording;
+ if (DeviceQuirks.get(MediaStoreVideoCannotWrite.class) != null) {
+ // Use FileOutputOption for devices in MediaStoreVideoCannotWrite Quirk.
+ pendingRecording = mVideoCapture.getOutput().prepareRecording(
+ this, generateFileOutputOptions());
+ } else {
+ // Use MediaStoreOutputOptions for public share media storage.
+ pendingRecording = mVideoCapture.getOutput().prepareRecording(
+ this, generateMediaStoreOutputOptions());
+ }
+ mRecording = pendingRecording
+ .asPersistentRecording() // Perform the recording as a persistent recording.
+ .start(ContextCompat.getMainExecutor(this),
+ videoRecordEvent -> {
+ if (videoRecordEvent instanceof VideoRecordEvent.Status) {
+ long currentDurationMillis = TimeUnit.NANOSECONDS.toMillis(
+ videoRecordEvent.getRecordingStats()
+ .getRecordedDurationNanos());
+ if (currentDurationMillis >= expectedSwitchTimeMillis) {
+ if (mNotYetSwitched) {
+ switchCamera();
+ mNotYetSwitched = false;
+ }
+ if (currentDurationMillis >= expectedDurationMillis) {
+ Preconditions.checkNotNull(mRecording, "The in-progress "
+ + "recording should not be null.");
+ mRecording.stop();
+ }
+ }
+ }
+ if (videoRecordEvent instanceof VideoRecordEvent.Finalize) {
+ mRecording = null;
+ mNotYetSwitched = true;
+ mStartButton.setClickable(true);
+ mStartButton.setText(R.string.record_button_idling);
+ mDurationText.setClickable(true);
+ mSwitchTimeText.setClickable(true);
+ }
+ });
+ }
+
+ @NonNull
+ private FileOutputOptions generateFileOutputOptions() {
+ String videoFileName = "video_" + System.currentTimeMillis() + ".mp4";
+ File videoFolder = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_MOVIES);
+ if (!videoFolder.exists() && !videoFolder.mkdirs()) {
+ Logger.e(TAG, "Failed to create directory: " + videoFolder);
+ }
+ return new FileOutputOptions.Builder(new File(videoFolder, videoFileName)).build();
+ }
+
+ @NonNull
+ private MediaStoreOutputOptions generateMediaStoreOutputOptions() {
+ String videoFileName = "video_" + System.currentTimeMillis();
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
+ contentValues.put(MediaStore.Video.Media.TITLE, videoFileName);
+ contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, videoFileName);
+ contentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
+ contentValues.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
+ return new MediaStoreOutputOptions.Builder(getContentResolver(),
+ MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
+ .setContentValues(contentValues)
+ .build();
+ }
+
+ private boolean allPermissionsGranted() {
+ for (String permission : REQUIRED_PERMISSIONS) {
+ if (ContextCompat.checkSelfPermission(this, permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode,
+ @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ if (requestCode == REQUEST_CODE_PERMISSIONS) {
+ if (allPermissionsGranted()) {
+ prepareCamera();
+ } else {
+ Toast.makeText(this, getString(R.string.permission_warning),
+ Toast.LENGTH_SHORT).show();
+ this.finish();
+ }
+ }
+ }
+}
diff --git a/camera/integration-tests/coretestapp/src/main/res/layout/activity_video_camera_switching.xml b/camera/integration-tests/coretestapp/src/main/res/layout/activity_video_camera_switching.xml
new file mode 100644
index 0000000..cfc8fe9
--- /dev/null
+++ b/camera/integration-tests/coretestapp/src/main/res/layout/activity_video_camera_switching.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/duration_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/duration_label" />
+
+ <EditText
+ android:id="@+id/duration"
+ android:layout_width="wrap_content"
+ android:layout_height="50dp"
+ android:layout_weight="1"
+ android:ems="10"
+ android:hint="@string/duration_label"
+ android:inputType="number" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/switch_time_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/switch_time_label" />
+
+ <EditText
+ android:id="@+id/switch_time"
+ android:layout_width="wrap_content"
+ android:layout_height="50dp"
+ android:layout_weight="1"
+ android:ems="10"
+ android:hint="@string/switch_time_label"
+ android:inputType="number" />
+ </LinearLayout>
+
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/start_recording"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:text="@string/record_button_idling" />
+
+ </LinearLayout>
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <androidx.camera.view.PreviewView
+ android:id="@+id/camera_preview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </FrameLayout>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/camera/integration-tests/coretestapp/src/main/res/values/strings.xml b/camera/integration-tests/coretestapp/src/main/res/values/strings.xml
index d54e0d1..b4fd308 100644
--- a/camera/integration-tests/coretestapp/src/main/res/values/strings.xml
+++ b/camera/integration-tests/coretestapp/src/main/res/values/strings.xml
@@ -25,4 +25,8 @@
<string name="is_front_primary">IsFrontPrimary</string>
<string name="permission_warning">Permissions not granted by the user.</string>
<string name="concurrent_not_supported_warning">Concurrent camera not supported</string>
+ <string name="record_button_idling">Start</string>
+ <string name="record_button_recording">Recording</string>
+ <string name="duration_label">Duration (ms)</string>
+ <string name="switch_time_label">Switch Time (ms)</string>
</resources>
\ No newline at end of file
diff --git a/car/app/app-automotive/api/1.4.0-beta01.txt b/car/app/app-automotive/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..33c4502
--- /dev/null
+++ b/car/app/app-automotive/api/1.4.0-beta01.txt
@@ -0,0 +1,101 @@
+// Signature format: 4.0
+package androidx.car.app.activity {
+
+ public abstract class BaseCarAppActivity extends androidx.fragment.app.FragmentActivity implements androidx.lifecycle.LifecycleOwner {
+ ctor public BaseCarAppActivity();
+ method public void bindToViewModel(androidx.car.app.SessionInfo);
+ method public android.content.ComponentName? getServiceComponentName();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public android.content.ComponentName? retrieveServiceComponentName();
+ }
+
+ public final class CarAppActivity extends androidx.car.app.activity.BaseCarAppActivity implements androidx.lifecycle.LifecycleOwner {
+ ctor public CarAppActivity();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class LauncherActivity extends androidx.fragment.app.FragmentActivity implements androidx.lifecycle.LifecycleOwner {
+ ctor public LauncherActivity();
+ }
+
+}
+
+package androidx.car.app.activity.renderer.surface {
+
+ @SuppressCompatibility public final class LegacySurfacePackage {
+ ctor public LegacySurfacePackage(androidx.car.app.activity.renderer.surface.SurfaceControlCallback);
+ }
+
+ public interface SurfaceControlCallback {
+ method public default void onError(String, Throwable);
+ method public void onKeyEvent(android.view.KeyEvent);
+ method public void onTouchEvent(android.view.MotionEvent);
+ method public void onWindowFocusChanged(boolean, boolean);
+ method public void setSurfaceWrapper(androidx.car.app.activity.renderer.surface.SurfaceWrapper);
+ }
+
+ @SuppressCompatibility public final class SurfaceWrapper {
+ ctor public SurfaceWrapper(android.os.IBinder?, @Dimension int, @Dimension int, int, int, android.view.Surface);
+ method public int getDensityDpi();
+ method public int getDisplayId();
+ method @Dimension public int getHeight();
+ method public android.os.IBinder? getHostToken();
+ method public android.view.Surface getSurface();
+ method @Dimension public int getWidth();
+ }
+
+}
+
+package androidx.car.app.hardware {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class AutomotiveCarHardwareManager implements androidx.car.app.hardware.CarHardwareManager {
+ ctor public AutomotiveCarHardwareManager(android.content.Context);
+ }
+
+}
+
+package androidx.car.app.hardware.common {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneAreaIdConstants {
+ field public static final int AREA_ID_GLOBAL = 0; // 0x0
+ }
+
+ public static final class CarZoneAreaIdConstants.VehicleAreaSeat {
+ field public static final int COL_ALL = 1911; // 0x777
+ field public static final int COL_CENTER = 546; // 0x222
+ field public static final int COL_LEFT = 273; // 0x111
+ field public static final int COL_RIGHT = 1092; // 0x444
+ field public static final int ROW_1_CENTER = 2; // 0x2
+ field public static final int ROW_1_LEFT = 1; // 0x1
+ field public static final int ROW_1_RIGHT = 4; // 0x4
+ field public static final int ROW_2_CENTER = 32; // 0x20
+ field public static final int ROW_2_LEFT = 16; // 0x10
+ field public static final int ROW_2_RIGHT = 64; // 0x40
+ field public static final int ROW_3_CENTER = 512; // 0x200
+ field public static final int ROW_3_LEFT = 256; // 0x100
+ field public static final int ROW_3_RIGHT = 1024; // 0x400
+ field public static final int ROW_ALL = 1911; // 0x777
+ field public static final int ROW_FIRST = 7; // 0x7
+ field public static final int ROW_SECOND = 112; // 0x70
+ field public static final int ROW_THIRD = 1792; // 0x700
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public interface CarZoneAreaIdConverter {
+ method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneUtils {
+ method public static com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int, int);
+ method public static androidx.car.app.hardware.common.CarZoneAreaIdConverter getZoneAreaIdConverter(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class GlobalCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+ ctor public GlobalCarZoneAreaIdConverter();
+ method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class SeatCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+ ctor public SeatCarZoneAreaIdConverter();
+ method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+ }
+
+}
+
diff --git a/car/app/app-automotive/api/res-1.4.0-beta01.txt b/car/app/app-automotive/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/car/app/app-automotive/api/res-1.4.0-beta01.txt
diff --git a/car/app/app-automotive/api/restricted_1.4.0-beta01.txt b/car/app/app-automotive/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..433cb93
--- /dev/null
+++ b/car/app/app-automotive/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1,101 @@
+// Signature format: 4.0
+package androidx.car.app.activity {
+
+ public abstract class BaseCarAppActivity extends androidx.fragment.app.FragmentActivity {
+ ctor public BaseCarAppActivity();
+ method public void bindToViewModel(androidx.car.app.SessionInfo);
+ method public android.content.ComponentName? getServiceComponentName();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public android.content.ComponentName? retrieveServiceComponentName();
+ }
+
+ public final class CarAppActivity extends androidx.car.app.activity.BaseCarAppActivity {
+ ctor public CarAppActivity();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class LauncherActivity extends androidx.fragment.app.FragmentActivity {
+ ctor public LauncherActivity();
+ }
+
+}
+
+package androidx.car.app.activity.renderer.surface {
+
+ @SuppressCompatibility public final class LegacySurfacePackage {
+ ctor public LegacySurfacePackage(androidx.car.app.activity.renderer.surface.SurfaceControlCallback);
+ }
+
+ public interface SurfaceControlCallback {
+ method public default void onError(String, Throwable);
+ method public void onKeyEvent(android.view.KeyEvent);
+ method public void onTouchEvent(android.view.MotionEvent);
+ method public void onWindowFocusChanged(boolean, boolean);
+ method public void setSurfaceWrapper(androidx.car.app.activity.renderer.surface.SurfaceWrapper);
+ }
+
+ @SuppressCompatibility public final class SurfaceWrapper {
+ ctor public SurfaceWrapper(android.os.IBinder?, @Dimension int, @Dimension int, int, int, android.view.Surface);
+ method public int getDensityDpi();
+ method public int getDisplayId();
+ method @Dimension public int getHeight();
+ method public android.os.IBinder? getHostToken();
+ method public android.view.Surface getSurface();
+ method @Dimension public int getWidth();
+ }
+
+}
+
+package androidx.car.app.hardware {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class AutomotiveCarHardwareManager implements androidx.car.app.hardware.CarHardwareManager {
+ ctor public AutomotiveCarHardwareManager(android.content.Context);
+ }
+
+}
+
+package androidx.car.app.hardware.common {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneAreaIdConstants {
+ field public static final int AREA_ID_GLOBAL = 0; // 0x0
+ }
+
+ public static final class CarZoneAreaIdConstants.VehicleAreaSeat {
+ field public static final int COL_ALL = 1911; // 0x777
+ field public static final int COL_CENTER = 546; // 0x222
+ field public static final int COL_LEFT = 273; // 0x111
+ field public static final int COL_RIGHT = 1092; // 0x444
+ field public static final int ROW_1_CENTER = 2; // 0x2
+ field public static final int ROW_1_LEFT = 1; // 0x1
+ field public static final int ROW_1_RIGHT = 4; // 0x4
+ field public static final int ROW_2_CENTER = 32; // 0x20
+ field public static final int ROW_2_LEFT = 16; // 0x10
+ field public static final int ROW_2_RIGHT = 64; // 0x40
+ field public static final int ROW_3_CENTER = 512; // 0x200
+ field public static final int ROW_3_LEFT = 256; // 0x100
+ field public static final int ROW_3_RIGHT = 1024; // 0x400
+ field public static final int ROW_ALL = 1911; // 0x777
+ field public static final int ROW_FIRST = 7; // 0x7
+ field public static final int ROW_SECOND = 112; // 0x70
+ field public static final int ROW_THIRD = 1792; // 0x700
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public interface CarZoneAreaIdConverter {
+ method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneUtils {
+ method public static com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int, int);
+ method public static androidx.car.app.hardware.common.CarZoneAreaIdConverter getZoneAreaIdConverter(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class GlobalCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+ ctor public GlobalCarZoneAreaIdConverter();
+ method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class SeatCarZoneAreaIdConverter implements androidx.car.app.hardware.common.CarZoneAreaIdConverter {
+ ctor public SeatCarZoneAreaIdConverter();
+ method public com.google.common.collect.ImmutableSet<androidx.car.app.hardware.common.CarZone!> convertAreaIdToCarZones(int);
+ }
+
+}
+
diff --git a/car/app/app-projected/api/1.4.0-beta01.txt b/car/app/app-projected/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/car/app/app-projected/api/1.4.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/car/app/app-projected/api/res-1.4.0-beta01.txt b/car/app/app-projected/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/car/app/app-projected/api/res-1.4.0-beta01.txt
diff --git a/car/app/app-projected/api/restricted_1.4.0-beta01.txt b/car/app/app-projected/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/car/app/app-projected/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-am/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-am/strings.xml
index e724acf..3bb95c8 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-am/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-am/strings.xml
@@ -164,7 +164,7 @@
<string name="take_520" msgid="3804796387195842741">"520 ውሰድ"</string>
<string name="gas_station" msgid="1203313937444666161">"ነዳጅ ማደያ"</string>
<string name="short_route" msgid="4831864276538141265">"አጭር መስመር"</string>
- <string name="less_busy" msgid="310625272281710983">"ያነሰ ስራ የሚበዛበት"</string>
+ <string name="less_busy" msgid="310625272281710983">"ያነሰ ሥራ የሚበዛበት"</string>
<string name="hov_friendly" msgid="6956152104754594971">"ለባለከፍተኛ መቀመጫ ተሽከርካሪ ምቹ"</string>
<string name="long_route" msgid="4737969235741057506">"ረጅም መንገድ"</string>
<string name="continue_start_nav" msgid="6231797535084469163">"ወደ አሰሳ ጀምር ቀጥል"</string>
@@ -326,7 +326,7 @@
<string name="sectioned_item_list_demo_title" msgid="1236735461225007729">"የተከፈለ ንጥል ዝርዝር ቅንጭብ ማሳያ"</string>
<string name="sectioned_item_list_one_title" msgid="6594204350307263338">"ዝርዝር 1"</string>
<string name="sectioned_item_list_two_title" msgid="4941545381743022833">"ዝርዝር 2"</string>
- <string name="sectioned_item_list_subtext" msgid="2963927693547537519">"ከእያንዳንዱ ዝርዝር ስር የግርጌ ጽሑፍ"</string>
+ <string name="sectioned_item_list_subtext" msgid="2963927693547537519">"ከእያንዳንዱ ዝርዝር ስር የግርጌ ጽሁፍ"</string>
<string name="empty_list_demo_title" msgid="5989013634820902455">"ባዶ የዝርዝር ቅንጭብ ማሳያ"</string>
<string name="empty_list_message" msgid="5331395517560728138">"ዝርዝሩ ባዶ ነው"</string>
<string name="misc_templates_demos_title" msgid="6077169010255928114">"የተለያዩ ቅንብር ደንቦች ቅንጭብ ማሳያዎች"</string>
diff --git a/car/app/app-samples/showcase/common/src/main/res/values-kn/strings.xml b/car/app/app-samples/showcase/common/src/main/res/values-kn/strings.xml
index 3cfdc4b..03c20c2 100644
--- a/car/app/app-samples/showcase/common/src/main/res/values-kn/strings.xml
+++ b/car/app/app-samples/showcase/common/src/main/res/values-kn/strings.xml
@@ -268,7 +268,7 @@
<string name="tab_template_no_tabs_demo_title" msgid="6907466201298082309">"ಟ್ಯಾಬ್ ಟೆಂಪ್ಲೇಟ್ ಯಾವುದೇ ಟ್ಯಾಬ್ಗಳ ಡೆಮೋ ಇಲ್ಲ"</string>
<string name="images_unknown_host_error" msgid="3180661817432720076">"ಅಪರಿಚಿತ ಹೋಸ್ಟ್ಗಾಗಿ ಚಿತ್ರಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲಾಗುವುದಿಲ್ಲ"</string>
<string name="icon_title_prefix" msgid="8487026131229541244">"ಐಕಾನ್"</string>
- <string name="content_provider_icons_demo_title" msgid="5708602618664311097">"ವಿಷಯ ಪೂರೈಕೆದಾರರ ಐಕಾನ್ಗಳ ಡೆಮೋ"</string>
+ <string name="content_provider_icons_demo_title" msgid="5708602618664311097">"ಕಂಟೆಂಟ್ ಪೂರೈಕೆದಾರರ ಐಕಾನ್ಗಳ ಡೆಮೋ"</string>
<string name="icons_demo_title" msgid="4082976685262307357">"ಐಕಾನ್ಗಳ ಡೆಮೋ"</string>
<string name="app_icon_title" msgid="7534936683349723423">"ಆ್ಯಪ್ ಐಕಾನ್"</string>
<string name="vector_no_tint_title" msgid="874591632279039146">"ಟಿಂಟ್ ಇಲ್ಲದೆ ಚಿತ್ರಿಸಬಹುದಾದ ಒಂದು ವೆಕ್ಟರ್"</string>
diff --git a/car/app/app-testing/api/1.4.0-beta01.txt b/car/app/app-testing/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..57cf025
--- /dev/null
+++ b/car/app/app-testing/api/1.4.0-beta01.txt
@@ -0,0 +1,66 @@
+// Signature format: 4.0
+package androidx.car.app.testing {
+
+ public class FakeHost {
+ method public void performNotificationActionClick(android.app.PendingIntent);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void setMicrophoneInputData(java.io.InputStream);
+ }
+
+ public class ScreenController {
+ ctor public ScreenController(androidx.car.app.Screen);
+ method public androidx.car.app.Screen getScreen();
+ method public Object? getScreenResult();
+ method public java.util.List<androidx.car.app.model.Template!> getTemplatesReturned();
+ method public androidx.car.app.testing.ScreenController moveToState(androidx.lifecycle.Lifecycle.State);
+ method public void reset();
+ }
+
+ public class SessionController {
+ ctor public SessionController(androidx.car.app.Session, androidx.car.app.testing.TestCarContext, android.content.Intent);
+ method public androidx.car.app.Session getSession();
+ method public androidx.car.app.testing.SessionController moveToState(androidx.lifecycle.Lifecycle.State);
+ }
+
+ public class TestAppManager extends androidx.car.app.AppManager {
+ method public androidx.car.app.SurfaceCallback? getSurfaceCallback();
+ method public java.util.List<android.util.Pair<androidx.car.app.Screen!,androidx.car.app.model.Template!>!> getTemplatesReturned();
+ method public java.util.List<java.lang.CharSequence!> getToastsShown();
+ method public void reset();
+ }
+
+ public class TestCarContext extends androidx.car.app.CarContext {
+ method public static androidx.car.app.testing.TestCarContext createCarContext(android.content.Context);
+ method public androidx.car.app.testing.FakeHost getFakeHost();
+ method public androidx.car.app.testing.TestCarContext.PermissionRequestInfo? getLastPermissionRequestInfo();
+ method public java.util.List<android.content.Intent!> getStartCarAppIntents();
+ method public boolean hasCalledFinishCarApp();
+ method public void reset();
+ }
+
+ public static class TestCarContext.PermissionRequestInfo {
+ method public androidx.car.app.OnRequestPermissionsListener getListener();
+ method public java.util.List<java.lang.String!> getPermissionsRequested();
+ }
+
+ public class TestScreenManager extends androidx.car.app.ScreenManager {
+ method public java.util.List<androidx.car.app.Screen!> getScreensPushed();
+ method public java.util.List<androidx.car.app.Screen!> getScreensRemoved();
+ method public boolean hasScreens();
+ method public void reset();
+ }
+
+}
+
+package androidx.car.app.testing.navigation {
+
+ public class TestNavigationManager extends androidx.car.app.navigation.NavigationManager {
+ ctor public TestNavigationManager(androidx.car.app.testing.TestCarContext, androidx.car.app.HostDispatcher);
+ method public int getNavigationEndedCount();
+ method public androidx.car.app.navigation.NavigationManagerCallback? getNavigationManagerCallback();
+ method public int getNavigationStartedCount();
+ method public java.util.List<androidx.car.app.navigation.model.Trip!> getTripsSent();
+ method public void reset();
+ }
+
+}
+
diff --git a/car/app/app-testing/api/res-1.4.0-beta01.txt b/car/app/app-testing/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/car/app/app-testing/api/res-1.4.0-beta01.txt
diff --git a/car/app/app-testing/api/restricted_1.4.0-beta01.txt b/car/app/app-testing/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..57cf025
--- /dev/null
+++ b/car/app/app-testing/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1,66 @@
+// Signature format: 4.0
+package androidx.car.app.testing {
+
+ public class FakeHost {
+ method public void performNotificationActionClick(android.app.PendingIntent);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void setMicrophoneInputData(java.io.InputStream);
+ }
+
+ public class ScreenController {
+ ctor public ScreenController(androidx.car.app.Screen);
+ method public androidx.car.app.Screen getScreen();
+ method public Object? getScreenResult();
+ method public java.util.List<androidx.car.app.model.Template!> getTemplatesReturned();
+ method public androidx.car.app.testing.ScreenController moveToState(androidx.lifecycle.Lifecycle.State);
+ method public void reset();
+ }
+
+ public class SessionController {
+ ctor public SessionController(androidx.car.app.Session, androidx.car.app.testing.TestCarContext, android.content.Intent);
+ method public androidx.car.app.Session getSession();
+ method public androidx.car.app.testing.SessionController moveToState(androidx.lifecycle.Lifecycle.State);
+ }
+
+ public class TestAppManager extends androidx.car.app.AppManager {
+ method public androidx.car.app.SurfaceCallback? getSurfaceCallback();
+ method public java.util.List<android.util.Pair<androidx.car.app.Screen!,androidx.car.app.model.Template!>!> getTemplatesReturned();
+ method public java.util.List<java.lang.CharSequence!> getToastsShown();
+ method public void reset();
+ }
+
+ public class TestCarContext extends androidx.car.app.CarContext {
+ method public static androidx.car.app.testing.TestCarContext createCarContext(android.content.Context);
+ method public androidx.car.app.testing.FakeHost getFakeHost();
+ method public androidx.car.app.testing.TestCarContext.PermissionRequestInfo? getLastPermissionRequestInfo();
+ method public java.util.List<android.content.Intent!> getStartCarAppIntents();
+ method public boolean hasCalledFinishCarApp();
+ method public void reset();
+ }
+
+ public static class TestCarContext.PermissionRequestInfo {
+ method public androidx.car.app.OnRequestPermissionsListener getListener();
+ method public java.util.List<java.lang.String!> getPermissionsRequested();
+ }
+
+ public class TestScreenManager extends androidx.car.app.ScreenManager {
+ method public java.util.List<androidx.car.app.Screen!> getScreensPushed();
+ method public java.util.List<androidx.car.app.Screen!> getScreensRemoved();
+ method public boolean hasScreens();
+ method public void reset();
+ }
+
+}
+
+package androidx.car.app.testing.navigation {
+
+ public class TestNavigationManager extends androidx.car.app.navigation.NavigationManager {
+ ctor public TestNavigationManager(androidx.car.app.testing.TestCarContext, androidx.car.app.HostDispatcher);
+ method public int getNavigationEndedCount();
+ method public androidx.car.app.navigation.NavigationManagerCallback? getNavigationManagerCallback();
+ method public int getNavigationStartedCount();
+ method public java.util.List<androidx.car.app.navigation.model.Trip!> getTripsSent();
+ method public void reset();
+ }
+
+}
+
diff --git a/car/app/app/api/1.4.0-beta01.txt b/car/app/app/api/1.4.0-beta01.txt
new file mode 100644
index 0000000..73c12de
--- /dev/null
+++ b/car/app/app/api/1.4.0-beta01.txt
@@ -0,0 +1,2210 @@
+// Signature format: 4.0
+package androidx.car.app {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class AppInfo {
+ ctor @VisibleForTesting public AppInfo(int, int, String);
+ method public int getLatestCarAppApiLevel();
+ method public String getLibraryDisplayVersion();
+ method public int getMinCarAppApiLevel();
+ field public static final String MIN_API_LEVEL_METADATA_KEY = "androidx.car.app.minCarApiLevel";
+ }
+
+ public class AppManager implements androidx.car.app.managers.Manager {
+ method @androidx.car.app.annotations.RequiresCarApi(5) public void dismissAlert(int);
+ method public void invalidate();
+ method public void setSurfaceCallback(androidx.car.app.SurfaceCallback?);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public void showAlert(androidx.car.app.model.Alert);
+ method public void showToast(CharSequence, int);
+ }
+
+ public final class CarAppPermission {
+ method public static void checkHasLibraryPermission(android.content.Context, String);
+ method public static void checkHasPermission(android.content.Context, String);
+ field public static final String ACCESS_SURFACE = "androidx.car.app.ACCESS_SURFACE";
+ field public static final String MAP_TEMPLATES = "androidx.car.app.MAP_TEMPLATES";
+ field public static final String NAVIGATION_TEMPLATES = "androidx.car.app.NAVIGATION_TEMPLATES";
+ }
+
+ public abstract class CarAppService extends android.app.Service {
+ ctor public CarAppService();
+ method public abstract androidx.car.app.validation.HostValidator createHostValidator();
+ method @CallSuper public final void dump(java.io.FileDescriptor, java.io.PrintWriter, String![]?);
+ method @Deprecated public final androidx.car.app.Session? getCurrentSession();
+ method public final androidx.car.app.HostInfo? getHostInfo();
+ method public final androidx.car.app.Session? getSession(androidx.car.app.SessionInfo);
+ method @CallSuper public final android.os.IBinder onBind(android.content.Intent);
+ method public androidx.car.app.Session onCreateSession();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.Session onCreateSession(androidx.car.app.SessionInfo);
+ method public final boolean onUnbind(android.content.Intent);
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_CALLING_APP = "androidx.car.app.category.CALLING";
+ field @Deprecated public static final String CATEGORY_CHARGING_APP = "androidx.car.app.category.CHARGING";
+ field @androidx.car.app.annotations.RequiresCarApi(6) public static final String CATEGORY_FEATURE_CLUSTER = "androidx.car.app.category.FEATURE_CLUSTER";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_IOT_APP = "androidx.car.app.category.IOT";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_MESSAGING_APP = "androidx.car.app.category.MESSAGING";
+ field public static final String CATEGORY_NAVIGATION_APP = "androidx.car.app.category.NAVIGATION";
+ field @Deprecated public static final String CATEGORY_PARKING_APP = "androidx.car.app.category.PARKING";
+ field public static final String CATEGORY_POI_APP = "androidx.car.app.category.POI";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_SETTINGS_APP = "androidx.car.app.category.SETTINGS";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_WEATHER_APP = "androidx.car.app.category.WEATHER";
+ field public static final String SERVICE_INTERFACE = "androidx.car.app.CarAppService";
+ }
+
+ public class CarContext extends android.content.ContextWrapper {
+ method public void finishCarApp();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public android.content.ComponentName? getCallingComponent();
+ method public int getCarAppApiLevel();
+ method public <T> T getCarService(Class<T!>);
+ method public Object getCarService(String);
+ method public String getCarServiceName(Class<?>);
+ method public androidx.car.app.HostInfo? getHostInfo();
+ method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ method public boolean isDarkMode();
+ method public void requestPermissions(java.util.List<java.lang.String!>, androidx.car.app.OnRequestPermissionsListener);
+ method public void requestPermissions(java.util.List<java.lang.String!>, java.util.concurrent.Executor, androidx.car.app.OnRequestPermissionsListener);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public void setCarAppResult(int, android.content.Intent?);
+ method public void startCarApp(android.content.Intent);
+ method @Deprecated public static void startCarApp(android.content.Intent, android.content.Intent);
+ field public static final String ACTION_NAVIGATE = "androidx.car.app.action.NAVIGATE";
+ field public static final String APP_SERVICE = "app";
+ field public static final String CAR_SERVICE = "car";
+ field @androidx.car.app.annotations.RequiresCarApi(2) public static final String CONSTRAINT_SERVICE = "constraints";
+ field public static final String EXTRA_START_CAR_APP_BINDER_KEY = "androidx.car.app.extra.START_CAR_APP_BINDER_KEY";
+ field @androidx.car.app.annotations.RequiresCarApi(3) public static final String HARDWARE_SERVICE = "hardware";
+ field public static final String NAVIGATION_SERVICE = "navigation";
+ field public static final String SCREEN_SERVICE = "screen";
+ field public static final String SUGGESTION_SERVICE = "suggestion";
+ }
+
+ public final class CarToast {
+ method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, @StringRes int, int);
+ method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, CharSequence, int);
+ method public void setDuration(int);
+ method public void setText(@StringRes int);
+ method public void setText(CharSequence);
+ method public void show();
+ field public static final int LENGTH_LONG = 1; // 0x1
+ field public static final int LENGTH_SHORT = 0; // 0x0
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class FailureResponse {
+ ctor public FailureResponse(Throwable);
+ method public int getErrorType();
+ method public String getStackTrace();
+ field public static final int BUNDLER_EXCEPTION = 1; // 0x1
+ field public static final int ILLEGAL_STATE_EXCEPTION = 2; // 0x2
+ field public static final int INVALID_PARAMETER_EXCEPTION = 3; // 0x3
+ field public static final int REMOTE_EXCEPTION = 6; // 0x6
+ field public static final int RUNTIME_EXCEPTION = 5; // 0x5
+ field public static final int SECURITY_EXCEPTION = 4; // 0x4
+ field public static final int UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class HandshakeInfo {
+ ctor public HandshakeInfo(String, int);
+ method public int getHostCarAppApiLevel();
+ method public String getHostPackageName();
+ }
+
+ public final class HostException extends java.lang.RuntimeException {
+ ctor public HostException(String);
+ ctor public HostException(String, Throwable);
+ ctor public HostException(Throwable);
+ }
+
+ public final class HostInfo {
+ ctor public HostInfo(String, int);
+ method public String getPackageName();
+ method public int getUid();
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnDoneCallback {
+ method public default void onFailure(androidx.car.app.serialization.Bundleable);
+ method public default void onSuccess(androidx.car.app.serialization.Bundleable?);
+ }
+
+ public interface OnRequestPermissionsListener {
+ method public void onRequestPermissionsResult(java.util.List<java.lang.String!>, java.util.List<java.lang.String!>);
+ }
+
+ public interface OnScreenResultListener {
+ method public void onScreenResult(Object?);
+ }
+
+ public abstract class Screen implements androidx.lifecycle.LifecycleOwner {
+ ctor protected Screen(androidx.car.app.CarContext);
+ method public final void finish();
+ method public final androidx.car.app.CarContext getCarContext();
+ method public final androidx.lifecycle.Lifecycle getLifecycle();
+ method public String? getMarker();
+ method public final androidx.car.app.ScreenManager getScreenManager();
+ method public final void invalidate();
+ method public abstract androidx.car.app.model.Template onGetTemplate();
+ method public void setMarker(String?);
+ method public void setResult(Object?);
+ }
+
+ @MainThread public class ScreenManager implements androidx.car.app.managers.Manager {
+ method public java.util.Collection<androidx.car.app.Screen!> getScreenStack();
+ method public int getStackSize();
+ method public androidx.car.app.Screen getTop();
+ method public void pop();
+ method public void popTo(String);
+ method public void popToRoot();
+ method public void push(androidx.car.app.Screen);
+ method public void pushForResult(androidx.car.app.Screen, androidx.car.app.OnScreenResultListener);
+ method public void remove(androidx.car.app.Screen);
+ }
+
+ public abstract class Session implements androidx.lifecycle.LifecycleOwner {
+ ctor public Session();
+ method public final androidx.car.app.CarContext getCarContext();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public void onCarConfigurationChanged(android.content.res.Configuration);
+ method public abstract androidx.car.app.Screen onCreateScreen(android.content.Intent);
+ method public void onNewIntent(android.content.Intent);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class SessionInfo {
+ ctor public SessionInfo(int, String);
+ method public int getDisplayType();
+ method public String getSessionId();
+ method public java.util.Set<java.lang.Class<? extends androidx.car.app.model.Template>!>? getSupportedTemplates(int);
+ field public static final androidx.car.app.SessionInfo DEFAULT_SESSION_INFO;
+ field public static final int DISPLAY_TYPE_CLUSTER = 1; // 0x1
+ field public static final int DISPLAY_TYPE_MAIN = 0; // 0x0
+ }
+
+ public class SessionInfoIntentEncoder {
+ method public static boolean containsSessionInfo(android.content.Intent);
+ method public static androidx.car.app.SessionInfo decode(android.content.Intent);
+ method public static void encode(androidx.car.app.SessionInfo, android.content.Intent);
+ }
+
+ public interface SurfaceCallback {
+ method @androidx.car.app.annotations.RequiresCarApi(5) public default void onClick(float, float);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public default void onFling(float, float);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScale(float, float, float);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScroll(float, float);
+ method public default void onStableAreaChanged(android.graphics.Rect);
+ method public default void onSurfaceAvailable(androidx.car.app.SurfaceContainer);
+ method public default void onSurfaceDestroyed(androidx.car.app.SurfaceContainer);
+ method public default void onVisibleAreaChanged(android.graphics.Rect);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SurfaceContainer {
+ ctor public SurfaceContainer(android.view.Surface?, int, int, int);
+ method public int getDpi();
+ method public int getHeight();
+ method public android.view.Surface? getSurface();
+ method public int getWidth();
+ }
+
+}
+
+package androidx.car.app.annotations {
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.PARAMETER}) public @interface CarProtocol {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface ExperimentalCarApi {
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface RequiresCarApi {
+ method public abstract int value();
+ }
+
+}
+
+package androidx.car.app.connection {
+
+ public final class CarConnection {
+ ctor @MainThread public CarConnection(android.content.Context);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
+ field public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+ field public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+ field public static final int CONNECTION_TYPE_NATIVE = 1; // 0x1
+ field public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; // 0x0
+ field public static final int CONNECTION_TYPE_PROJECTION = 2; // 0x2
+ }
+
+}
+
+package androidx.car.app.constraints {
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public class ConstraintManager implements androidx.car.app.managers.Manager {
+ method public int getContentLimit(int);
+ method @androidx.car.app.annotations.RequiresCarApi(6) public boolean isAppDrivenRefreshEnabled();
+ field public static final int CONTENT_LIMIT_TYPE_GRID = 1; // 0x1
+ field public static final int CONTENT_LIMIT_TYPE_LIST = 0; // 0x0
+ field public static final int CONTENT_LIMIT_TYPE_PANE = 4; // 0x4
+ field public static final int CONTENT_LIMIT_TYPE_PLACE_LIST = 2; // 0x2
+ field public static final int CONTENT_LIMIT_TYPE_ROUTE_LIST = 3; // 0x3
+ }
+
+}
+
+package androidx.car.app.hardware {
+
+ @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarHardwareManager extends androidx.car.app.managers.Manager {
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public default androidx.car.app.hardware.climate.CarClimate getCarClimate();
+ method public default androidx.car.app.hardware.info.CarInfo getCarInfo();
+ method public default androidx.car.app.hardware.info.CarSensors getCarSensors();
+ }
+
+}
+
+package androidx.car.app.hardware.climate {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CabinTemperatureProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!> getCarZoneSetsToCabinCelsiusTemperatureRanges();
+ method public float getCelsiusSupportedIncrement();
+ method public float getFahrenheitSupportedIncrement();
+ method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxCelsiusRange();
+ method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxFahrenheitRange();
+ method public boolean hasCarZoneSetsToCabinCelsiusTemperatureRanges();
+ method public boolean hasCelsiusSupportedIncrement();
+ method public boolean hasFahrenheitSupportedIncrement();
+ method public boolean hasSupportedMinMaxCelsiusRange();
+ method public boolean hasSupportedMinMaxFahrenheitRange();
+ }
+
+ public static final class CabinTemperatureProfile.Builder {
+ ctor public CabinTemperatureProfile.Builder();
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile build();
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCarZoneSetsToCabinCelsiusTemperatureRanges(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!>);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCelsiusSupportedIncrement(float);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setFahrenheitSupportedIncrement(float);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxCelsiusRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxFahrenheitRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+ }
+
+ @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimate {
+ method public void fetchClimateProfile(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateProfileRequest, androidx.car.app.hardware.climate.CarClimateProfileCallback);
+ method public void registerClimateStateCallback(java.util.concurrent.Executor, androidx.car.app.hardware.climate.RegisterClimateStateRequest, androidx.car.app.hardware.climate.CarClimateStateCallback);
+ method public <E> void setClimateState(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateStateRequest<E!>, androidx.car.app.hardware.common.CarSetOperationStatusCallback);
+ method public void unregisterClimateStateCallback(androidx.car.app.hardware.climate.CarClimateStateCallback);
+ }
+
+ @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarClimateFeature {
+ method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+ method public int getFeature();
+ }
+
+ public static final class CarClimateFeature.Builder {
+ ctor public CarClimateFeature.Builder(int);
+ method public androidx.car.app.hardware.climate.CarClimateFeature.Builder addCarZones(androidx.car.app.hardware.common.CarZone!...);
+ method public androidx.car.app.hardware.climate.CarClimateFeature build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateProfileCallback {
+ method public default void onCabinTemperatureProfileAvailable(androidx.car.app.hardware.climate.CabinTemperatureProfile);
+ method public default void onCarZoneMappingInfoProfileAvailable(androidx.car.app.hardware.climate.CarZoneMappingInfoProfile);
+ method public default void onDefrosterProfileAvailable(androidx.car.app.hardware.climate.DefrosterProfile);
+ method public default void onElectricDefrosterProfileAvailable(androidx.car.app.hardware.climate.ElectricDefrosterProfile);
+ method public default void onFanDirectionProfileAvailable(androidx.car.app.hardware.climate.FanDirectionProfile);
+ method public default void onFanSpeedLevelProfileAvailable(androidx.car.app.hardware.climate.FanSpeedLevelProfile);
+ method public default void onHvacAcProfileAvailable(androidx.car.app.hardware.climate.HvacAcProfile);
+ method public default void onHvacAutoModeProfileAvailable(androidx.car.app.hardware.climate.HvacAutoModeProfile);
+ method public default void onHvacAutoRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacAutoRecirculationProfile);
+ method public default void onHvacDualModeProfileAvailable(androidx.car.app.hardware.climate.HvacDualModeProfile);
+ method public default void onHvacMaxAcModeProfileAvailable(androidx.car.app.hardware.climate.HvacMaxAcModeProfile);
+ method public default void onHvacPowerProfileAvailable(androidx.car.app.hardware.climate.HvacPowerProfile);
+ method public default void onHvacRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacRecirculationProfile);
+ method public default void onMaxDefrosterProfileAvailable(androidx.car.app.hardware.climate.MaxDefrosterProfile);
+ method public default void onSeatTemperatureLevelProfileAvailable(androidx.car.app.hardware.climate.SeatTemperatureProfile);
+ method public default void onSeatVentilationLevelProfileAvailable(androidx.car.app.hardware.climate.SeatVentilationProfile);
+ method public default void onSteeringWheelHeatProfileAvailable(androidx.car.app.hardware.climate.SteeringWheelHeatProfile);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateStateCallback {
+ method public default void onCabinTemperatureStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public default void onDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onElectricDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onFanDirectionStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onFanSpeedLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onHvacAcStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacAutoModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacAutoRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacDualModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacMaxAcModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacPowerStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onMaxDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onSeatTemperatureLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onSeatVentilationLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onSteeringWheelHeatStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneMappingInfoProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class CarZoneMappingInfoProfile.Builder {
+ ctor public CarZoneMappingInfoProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.CarZoneMappingInfoProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateProfileRequest {
+ method public java.util.Set<java.lang.Integer!> getAllClimateProfiles();
+ method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateProfileFeatures();
+ field public static final int FEATURE_CABIN_TEMPERATURE = 4; // 0x4
+ field public static final int FEATURE_CAR_ZONE_MAPPING = 17; // 0x11
+ field public static final int FEATURE_FAN_DIRECTION = 6; // 0x6
+ field public static final int FEATURE_FAN_SPEED = 5; // 0x5
+ field public static final int FEATURE_HVAC_AC = 2; // 0x2
+ field public static final int FEATURE_HVAC_AUTO_MODE = 12; // 0xc
+ field public static final int FEATURE_HVAC_AUTO_RECIRCULATION = 11; // 0xb
+ field public static final int FEATURE_HVAC_DEFROSTER = 14; // 0xe
+ field public static final int FEATURE_HVAC_DUAL_MODE = 13; // 0xd
+ field public static final int FEATURE_HVAC_ELECTRIC_DEFROSTER = 16; // 0x10
+ field public static final int FEATURE_HVAC_MAX_AC = 3; // 0x3
+ field public static final int FEATURE_HVAC_MAX_DEFROSTER = 15; // 0xf
+ field public static final int FEATURE_HVAC_POWER = 1; // 0x1
+ field public static final int FEATURE_HVAC_RECIRCULATION = 10; // 0xa
+ field public static final int FEATURE_SEAT_TEMPERATURE_LEVEL = 7; // 0x7
+ field public static final int FEATURE_SEAT_VENTILATION_LEVEL = 8; // 0x8
+ field public static final int FEATURE_STEERING_WHEEL_HEAT = 9; // 0x9
+ }
+
+ public static final class ClimateProfileRequest.Builder {
+ ctor public ClimateProfileRequest.Builder();
+ method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder addClimateProfileFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+ method public androidx.car.app.hardware.climate.ClimateProfileRequest build();
+ method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder setAllClimateProfiles();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateStateRequest<T> {
+ method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+ method public int getRequestedFeature();
+ method public T getRequestedValue();
+ }
+
+ public static final class ClimateStateRequest.Builder<T> {
+ ctor public ClimateStateRequest.Builder(int, T!);
+ method public androidx.car.app.hardware.climate.ClimateStateRequest.Builder<T!> addCarZones(androidx.car.app.hardware.common.CarZone);
+ method public androidx.car.app.hardware.climate.ClimateStateRequest<T!> build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class DefrosterProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class DefrosterProfile.Builder {
+ ctor public DefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.DefrosterProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class ElectricDefrosterProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class ElectricDefrosterProfile.Builder {
+ ctor public ElectricDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.ElectricDefrosterProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanDirectionProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!> getCarZoneSetsToFanDirectionValues();
+ }
+
+ public static final class FanDirectionProfile.Builder {
+ ctor public FanDirectionProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.FanDirectionProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanSpeedLevelProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToFanSpeedLevelRanges();
+ }
+
+ public static final class FanSpeedLevelProfile.Builder {
+ ctor public FanSpeedLevelProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.FanSpeedLevelProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAcProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacAcProfile.Builder {
+ ctor public HvacAcProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacAcProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoModeProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacAutoModeProfile.Builder {
+ ctor public HvacAutoModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacAutoModeProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoRecirculationProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacAutoRecirculationProfile.Builder {
+ ctor public HvacAutoRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacAutoRecirculationProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacDualModeProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacDualModeProfile.Builder {
+ ctor public HvacDualModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacDualModeProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacMaxAcModeProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacMaxAcModeProfile.Builder {
+ ctor public HvacMaxAcModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacMaxAcModeProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacPowerProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacPowerProfile.Builder {
+ ctor public HvacPowerProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacPowerProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacRecirculationProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZones();
+ }
+
+ public static final class HvacRecirculationProfile.Builder {
+ ctor public HvacRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacRecirculationProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class MaxDefrosterProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class MaxDefrosterProfile.Builder {
+ ctor public MaxDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.MaxDefrosterProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class RegisterClimateStateRequest {
+ method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateRegisterFeatures();
+ }
+
+ public static final class RegisterClimateStateRequest.Builder {
+ ctor public RegisterClimateStateRequest.Builder(boolean);
+ method public androidx.car.app.hardware.climate.RegisterClimateStateRequest.Builder addClimateRegisterFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+ method public androidx.car.app.hardware.climate.RegisterClimateStateRequest build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatTemperatureProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatTemperatureValues();
+ }
+
+ public static final class SeatTemperatureProfile.Builder {
+ ctor public SeatTemperatureProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.SeatTemperatureProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatVentilationProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatVentilationValues();
+ }
+
+ public static final class SeatVentilationProfile.Builder {
+ ctor public SeatVentilationProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.SeatVentilationProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SteeringWheelHeatProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSteeringWheelHeatValues();
+ }
+
+ public static final class SteeringWheelHeatProfile.Builder {
+ ctor public SteeringWheelHeatProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.SteeringWheelHeatProfile build();
+ }
+
+}
+
+package androidx.car.app.hardware.common {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarSetOperationStatusCallback {
+ method public default void onSetCarClimateStateCabinTemperature(int);
+ method public default void onSetCarClimateStateDefroster(int);
+ method public default void onSetCarClimateStateElectricDefroster(int);
+ method public default void onSetCarClimateStateFanDirection(int);
+ method public default void onSetCarClimateStateFanSpeedLevel(int);
+ method public default void onSetCarClimateStateHvacAc(int);
+ method public default void onSetCarClimateStateHvacAutoMode(int);
+ method public default void onSetCarClimateStateHvacAutoRecirculation(int);
+ method public default void onSetCarClimateStateHvacDualMode(int);
+ method public default void onSetCarClimateStateHvacMaxAcMode(int);
+ method public default void onSetCarClimateStateHvacPower(int);
+ method public default void onSetCarClimateStateHvacRecirculation(int);
+ method public default void onSetCarClimateStateMaxDefroster(int);
+ method public default void onSetCarClimateStateSeatTemperatureLevel(int);
+ method public default void onSetCarClimateStateSeatVentilationLevel(int);
+ method public default void onSetCarClimateStateSteeringWheelHeat(int);
+ method public static String toString(int);
+ field public static final int OPERATION_STATUS_FEATURE_SETTING_NOT_ALLOWED = 4; // 0x4
+ field public static final int OPERATION_STATUS_FEATURE_TEMPORARILY_UNAVAILABLE = 3; // 0x3
+ field public static final int OPERATION_STATUS_FEATURE_UNIMPLEMENTED = 1; // 0x1
+ field public static final int OPERATION_STATUS_FEATURE_UNSUPPORTED = 2; // 0x2
+ field public static final int OPERATION_STATUS_ILLEGAL_CAR_HARDWARE_STATE = 7; // 0x7
+ field public static final int OPERATION_STATUS_INSUFFICIENT_PERMISSION = 6; // 0x6
+ field public static final int OPERATION_STATUS_SUCCESS = 0; // 0x0
+ field public static final int OPERATION_STATUS_UNSUPPORTED_VALUE = 5; // 0x5
+ field public static final int OPERATION_STATUS_UPDATE_TIMEOUT = 8; // 0x8
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarUnit {
+ method public static String toString(int);
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int IMPERIAL_GALLON = 204; // 0xcc
+ field public static final int KILOMETER = 3; // 0x3
+ field public static final int KILOMETERS_PER_HOUR = 102; // 0x66
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int LITER = 202; // 0xca
+ field public static final int METER = 2; // 0x2
+ field public static final int METERS_PER_SEC = 101; // 0x65
+ field public static final int MILE = 4; // 0x4
+ field public static final int MILES_PER_HOUR = 103; // 0x67
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int MILLILITER = 201; // 0xc9
+ field public static final int MILLIMETER = 1; // 0x1
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int US_GALLON = 203; // 0xcb
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarValue<T> {
+ ctor public CarValue(T?, long, int);
+ ctor @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public CarValue(T?, long, int, java.util.List<androidx.car.app.hardware.common.CarZone!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+ method public int getStatus();
+ method public long getTimestampMillis();
+ method public T? getValue();
+ field public static final int STATUS_SUCCESS = 1; // 0x1
+ field public static final int STATUS_UNAVAILABLE = 3; // 0x3
+ field public static final int STATUS_UNIMPLEMENTED = 2; // 0x2
+ field public static final int STATUS_UNKNOWN = 0; // 0x0
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarZone {
+ method public int getColumn();
+ method public int getRow();
+ field public static final int CAR_ZONE_COLUMN_ALL = 16; // 0x10
+ field public static final int CAR_ZONE_COLUMN_CENTER = 48; // 0x30
+ field public static final int CAR_ZONE_COLUMN_DRIVER = 80; // 0x50
+ field public static final int CAR_ZONE_COLUMN_LEFT = 32; // 0x20
+ field public static final int CAR_ZONE_COLUMN_PASSENGER = 96; // 0x60
+ field public static final int CAR_ZONE_COLUMN_RIGHT = 64; // 0x40
+ field public static final androidx.car.app.hardware.common.CarZone CAR_ZONE_GLOBAL;
+ field public static final int CAR_ZONE_ROW_ALL = 0; // 0x0
+ field public static final int CAR_ZONE_ROW_EXCLUDE_FIRST = 4; // 0x4
+ field public static final int CAR_ZONE_ROW_FIRST = 1; // 0x1
+ field public static final int CAR_ZONE_ROW_SECOND = 2; // 0x2
+ field public static final int CAR_ZONE_ROW_THIRD = 3; // 0x3
+ }
+
+ public static final class CarZone.Builder {
+ ctor public CarZone.Builder();
+ method public androidx.car.app.hardware.common.CarZone build();
+ method public androidx.car.app.hardware.common.CarZone.Builder setColumn(int);
+ method public androidx.car.app.hardware.common.CarZone.Builder setRow(int);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public interface OnCarDataAvailableListener<T> {
+ method public void onCarDataAvailable(T);
+ }
+
+}
+
+package androidx.car.app.hardware.info {
+
+ @SuppressCompatibility @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.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getForces();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarHardwareLocation {
+ ctor public CarHardwareLocation(androidx.car.app.hardware.common.CarValue<android.location.Location!>);
+ method public androidx.car.app.hardware.common.CarValue<android.location.Location!> getLocation();
+ }
+
+ @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarInfo {
+ method public void addEnergyLevelListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void addEvStatusListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+ method public void addMileageListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+ method public void addSpeedListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+ method public void addTollListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+ method public void fetchEnergyProfile(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyProfile!>);
+ method public void fetchModel(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Model!>);
+ method public void removeEnergyLevelListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void removeEvStatusListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+ method public void removeMileageListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+ method public void removeSpeedListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+ method public void removeTollListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+ }
+
+ @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarSensors {
+ method public void addAccelerometerListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+ method public void addCarHardwareLocationListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+ method public void addCompassListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+ method public void addGyroscopeListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+ method public void removeAccelerometerListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+ method public void removeCarHardwareLocationListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+ method public void removeCompassListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+ method public void removeGyroscopeListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+ field public static final int UPDATE_RATE_FASTEST = 3; // 0x3
+ field public static final int UPDATE_RATE_NORMAL = 1; // 0x1
+ field public static final int UPDATE_RATE_UI = 2; // 0x2
+ }
+
+ @SuppressCompatibility @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.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getOrientations();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyLevel {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getBatteryPercent();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEnergyIsLow();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getFuelPercent();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getFuelVolumeDisplayUnit();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRangeRemainingMeters();
+ }
+
+ public static final class EnergyLevel.Builder {
+ ctor public EnergyLevel.Builder();
+ method public androidx.car.app.hardware.info.EnergyLevel build();
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setBatteryPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setEnergyIsLow(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelVolumeDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setRangeRemainingMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyProfile {
+ 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
+ field public static final int EVCONNECTOR_TYPE_GBT = 9; // 0x9
+ field public static final int EVCONNECTOR_TYPE_GBT_DC = 10; // 0xa
+ field public static final int EVCONNECTOR_TYPE_J1772 = 1; // 0x1
+ field public static final int EVCONNECTOR_TYPE_MENNEKES = 2; // 0x2
+ field public static final int EVCONNECTOR_TYPE_OTHER = 101; // 0x65
+ field public static final int EVCONNECTOR_TYPE_SCAME = 11; // 0xb
+ field public static final int EVCONNECTOR_TYPE_TESLA_HPWC = 7; // 0x7
+ field public static final int EVCONNECTOR_TYPE_TESLA_ROADSTER = 6; // 0x6
+ field public static final int EVCONNECTOR_TYPE_TESLA_SUPERCHARGER = 8; // 0x8
+ field public static final int EVCONNECTOR_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int FUEL_TYPE_BIODIESEL = 5; // 0x5
+ field public static final int FUEL_TYPE_CNG = 8; // 0x8
+ field public static final int FUEL_TYPE_DIESEL_1 = 3; // 0x3
+ field public static final int FUEL_TYPE_DIESEL_2 = 4; // 0x4
+ field public static final int FUEL_TYPE_E85 = 6; // 0x6
+ field public static final int FUEL_TYPE_ELECTRIC = 10; // 0xa
+ field public static final int FUEL_TYPE_HYDROGEN = 11; // 0xb
+ field public static final int FUEL_TYPE_LEADED = 2; // 0x2
+ field public static final int FUEL_TYPE_LNG = 9; // 0x9
+ field public static final int FUEL_TYPE_LPG = 7; // 0x7
+ field public static final int FUEL_TYPE_OTHER = 12; // 0xc
+ field public static final int FUEL_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int FUEL_TYPE_UNLEADED = 1; // 0x1
+ }
+
+ 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.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!>!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public class EvStatus {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortConnected();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortOpen();
+ }
+
+ public static final class EvStatus.Builder {
+ ctor public EvStatus.Builder();
+ method public androidx.car.app.hardware.info.EvStatus build();
+ method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortConnected(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortOpen(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ }
+
+ @SuppressCompatibility @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.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getRotations();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Mileage {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getOdometerMeters();
+ }
+
+ public static final class Mileage.Builder {
+ ctor public Mileage.Builder();
+ method public androidx.car.app.hardware.info.Mileage build();
+ method public androidx.car.app.hardware.info.Mileage.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public androidx.car.app.hardware.info.Mileage.Builder setOdometerMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Model {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getManufacturer();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getName();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getYear();
+ }
+
+ public static final class Model.Builder {
+ ctor public Model.Builder();
+ method public androidx.car.app.hardware.info.Model build();
+ method public androidx.car.app.hardware.info.Model.Builder setManufacturer(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+ method public androidx.car.app.hardware.info.Model.Builder setName(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+ method public androidx.car.app.hardware.info.Model.Builder setYear(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Speed {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getDisplaySpeedMetersPerSecond();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRawSpeedMetersPerSecond();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getSpeedDisplayUnit();
+ }
+
+ public static final class Speed.Builder {
+ ctor public Speed.Builder();
+ method public androidx.car.app.hardware.info.Speed build();
+ method public androidx.car.app.hardware.info.Speed.Builder setDisplaySpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public androidx.car.app.hardware.info.Speed.Builder setRawSpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public androidx.car.app.hardware.info.Speed.Builder setSpeedDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class TollCard {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getCardState();
+ field public static final int TOLLCARD_STATE_INVALID = 2; // 0x2
+ field public static final int TOLLCARD_STATE_NOT_INSERTED = 3; // 0x3
+ field public static final int TOLLCARD_STATE_UNKNOWN = 0; // 0x0
+ field public static final int TOLLCARD_STATE_VALID = 1; // 0x1
+ }
+
+ public static final class TollCard.Builder {
+ ctor public TollCard.Builder();
+ method public androidx.car.app.hardware.info.TollCard build();
+ method public androidx.car.app.hardware.info.TollCard.Builder setCardState(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ }
+
+}
+
+package androidx.car.app.managers {
+
+ public interface Manager {
+ }
+
+}
+
+package androidx.car.app.media {
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public interface CarAudioCallback {
+ method public void onStopRecording();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public class CarAudioCallbackDelegate {
+ method public void onStopRecording();
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public abstract class CarAudioRecord {
+ method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public static androidx.car.app.media.CarAudioRecord create(androidx.car.app.CarContext);
+ method public int read(byte[], int, int);
+ method public void startRecording();
+ method public void stopRecording();
+ field public static final int AUDIO_CONTENT_BUFFER_SIZE = 512; // 0x200
+ field public static final String AUDIO_CONTENT_MIME = "audio/l16";
+ field public static final int AUDIO_CONTENT_SAMPLING_RATE = 16000; // 0x3e80
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneRequest {
+ method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallbackDelegate();
+ }
+
+ public static final class OpenMicrophoneRequest.Builder {
+ ctor public OpenMicrophoneRequest.Builder(androidx.car.app.media.CarAudioCallback);
+ method public androidx.car.app.media.OpenMicrophoneRequest build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneResponse {
+ method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallback();
+ method public java.io.InputStream getCarMicrophoneInputStream();
+ }
+
+ public static final class OpenMicrophoneResponse.Builder {
+ ctor public OpenMicrophoneResponse.Builder(androidx.car.app.media.CarAudioCallback);
+ method public androidx.car.app.media.OpenMicrophoneResponse build();
+ method public androidx.car.app.media.OpenMicrophoneResponse.Builder setCarMicrophoneDescriptor(android.os.ParcelFileDescriptor);
+ }
+
+}
+
+package androidx.car.app.mediaextensions {
+
+ public final class MetadataExtras {
+ field public static final String KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI";
+ field public static final String KEY_DESCRIPTION_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_DESCRIPTION_LINK_MEDIA_ID";
+ field public static final String KEY_IMMERSIVE_AUDIO = "androidx.car.app.mediaextensions.KEY_IMMERSIVE_AUDIO";
+ field public static final String KEY_SUBTITLE_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_SUBTITLE_LINK_MEDIA_ID";
+ }
+
+}
+
+package androidx.car.app.messaging {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class MessagingServiceConstants {
+ field public static final String ACTION_HANDLE_CAR_MESSAGING = "androidx.car.app.messaging.action.HANDLE_CAR_MESSAGING";
+ }
+
+}
+
+package androidx.car.app.messaging.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class CarMessage {
+ method public androidx.car.app.model.CarText? getBody();
+ method public String? getMultimediaMimeType();
+ method public android.net.Uri? getMultimediaUri();
+ method public long getReceivedTimeEpochMillis();
+ method public androidx.core.app.Person? getSender();
+ method public boolean isRead();
+ }
+
+ public static final class CarMessage.Builder {
+ ctor public CarMessage.Builder();
+ method public androidx.car.app.messaging.model.CarMessage build();
+ method public androidx.car.app.messaging.model.CarMessage.Builder setBody(androidx.car.app.model.CarText?);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaMimeType(String?);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaUri(android.net.Uri?);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setRead(boolean);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setReceivedTimeEpochMillis(long);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setSender(androidx.core.app.Person?);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public interface ConversationCallback {
+ method public void onMarkAsRead();
+ method public void onTextReply(String);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public interface ConversationCallbackDelegate {
+ method public void sendMarkAsRead(androidx.car.app.OnDoneCallback);
+ method public void sendTextReply(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class ConversationItem implements androidx.car.app.model.Item {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.messaging.model.ConversationCallbackDelegate getConversationCallbackDelegate();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public String getId();
+ method public java.util.List<androidx.car.app.messaging.model.CarMessage!> getMessages();
+ method public androidx.core.app.Person getSelf();
+ method public androidx.car.app.model.CarText getTitle();
+ method public boolean isGroupConversation();
+ }
+
+ public static final class ConversationItem.Builder {
+ ctor public ConversationItem.Builder();
+ ctor public ConversationItem.Builder(androidx.car.app.messaging.model.ConversationItem);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.messaging.model.ConversationItem build();
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setConversationCallback(androidx.car.app.messaging.model.ConversationCallback);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setGroupConversation(boolean);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setId(String);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setMessages(java.util.List<androidx.car.app.messaging.model.CarMessage!>);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setSelf(androidx.core.app.Person);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setTitle(androidx.car.app.model.CarText);
+ }
+
+}
+
+package androidx.car.app.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Action {
+ method public androidx.car.app.model.CarColor? getBackgroundColor();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public int getFlags();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public int getType();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+ method public boolean isStandard();
+ method public static String typeToString(int);
+ field public static final androidx.car.app.model.Action APP_ICON;
+ field public static final androidx.car.app.model.Action BACK;
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.Action COMPOSE_MESSAGE;
+ field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_DEFAULT = 4; // 0x4
+ field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_IS_PERSISTENT = 2; // 0x2
+ field @androidx.car.app.annotations.RequiresCarApi(4) public static final int FLAG_PRIMARY = 1; // 0x1
+ field public static final androidx.car.app.model.Action PAN;
+ field public static final int TYPE_APP_ICON = 65538; // 0x10002
+ field public static final int TYPE_BACK = 65539; // 0x10003
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int TYPE_COMPOSE_MESSAGE = 65541; // 0x10005
+ field public static final int TYPE_CUSTOM = 1; // 0x1
+ field public static final int TYPE_PAN = 65540; // 0x10004
+ }
+
+ public static final class Action.Builder {
+ ctor public Action.Builder();
+ ctor @androidx.car.app.annotations.RequiresCarApi(2) public Action.Builder(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Action build();
+ method public androidx.car.app.model.Action.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Action.Builder setEnabled(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Action.Builder setFlags(int);
+ method public androidx.car.app.model.Action.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Action.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.Action.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Action.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ActionStrip {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getFirstActionOfType(int);
+ }
+
+ public static final class ActionStrip.Builder {
+ ctor public ActionStrip.Builder();
+ method public androidx.car.app.model.ActionStrip.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.ActionStrip build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Alert {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.AlertCallbackDelegate? getCallbackDelegate();
+ method public long getDurationMillis();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public int getId();
+ method public androidx.car.app.model.CarText? getSubtitle();
+ method public androidx.car.app.model.CarText getTitle();
+ }
+
+ public static final class Alert.Builder {
+ ctor public Alert.Builder(int, androidx.car.app.model.CarText, long);
+ method public androidx.car.app.model.Alert.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Alert build();
+ method public androidx.car.app.model.Alert.Builder setCallback(androidx.car.app.model.AlertCallback);
+ method public androidx.car.app.model.Alert.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Alert.Builder setSubtitle(androidx.car.app.model.CarText);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallback {
+ method public void onCancel(int);
+ method public void onDismiss();
+ field public static final int REASON_NOT_SUPPORTED = 3; // 0x3
+ field public static final int REASON_TIMEOUT = 1; // 0x1
+ field public static final int REASON_USER_ACTION = 2; // 0x2
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallbackDelegate {
+ method public void sendCancel(int, androidx.car.app.OnDoneCallback);
+ method public void sendDismiss(androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class Badge {
+ method public androidx.car.app.model.CarColor? getBackgroundColor();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public boolean hasDot();
+ }
+
+ public static final class Badge.Builder {
+ ctor public Badge.Builder();
+ method public androidx.car.app.model.Badge build();
+ method public androidx.car.app.model.Badge.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.model.Badge.Builder setHasDot(boolean);
+ method public androidx.car.app.model.Badge.Builder setIcon(androidx.car.app.model.CarIcon);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarColor {
+ method public static androidx.car.app.model.CarColor createCustom(@ColorInt int, @ColorInt int);
+ method @ColorInt public int getColor();
+ method @ColorInt public int getColorDark();
+ method public int getType();
+ field public static final androidx.car.app.model.CarColor BLUE;
+ field public static final androidx.car.app.model.CarColor DEFAULT;
+ field public static final androidx.car.app.model.CarColor GREEN;
+ field public static final androidx.car.app.model.CarColor PRIMARY;
+ field public static final androidx.car.app.model.CarColor RED;
+ field public static final androidx.car.app.model.CarColor SECONDARY;
+ field public static final int TYPE_BLUE = 6; // 0x6
+ field public static final int TYPE_CUSTOM = 0; // 0x0
+ field public static final int TYPE_DEFAULT = 1; // 0x1
+ field public static final int TYPE_GREEN = 5; // 0x5
+ field public static final int TYPE_PRIMARY = 2; // 0x2
+ field public static final int TYPE_RED = 4; // 0x4
+ field public static final int TYPE_SECONDARY = 3; // 0x3
+ field public static final int TYPE_YELLOW = 7; // 0x7
+ field public static final androidx.car.app.model.CarColor YELLOW;
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIcon {
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public androidx.car.app.model.CarColor? getTint();
+ method public int getType();
+ field public static final androidx.car.app.model.CarIcon ALERT;
+ field public static final androidx.car.app.model.CarIcon APP_ICON;
+ field public static final androidx.car.app.model.CarIcon BACK;
+ field @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.CarIcon COMPOSE_MESSAGE;
+ field public static final androidx.car.app.model.CarIcon ERROR;
+ field @androidx.car.app.annotations.RequiresCarApi(2) public static final androidx.car.app.model.CarIcon PAN;
+ field public static final int TYPE_ALERT = 4; // 0x4
+ field public static final int TYPE_APP_ICON = 5; // 0x5
+ field public static final int TYPE_BACK = 3; // 0x3
+ field public static final int TYPE_COMPOSE_MESSAGE = 8; // 0x8
+ field public static final int TYPE_CUSTOM = 1; // 0x1
+ field public static final int TYPE_ERROR = 6; // 0x6
+ field public static final int TYPE_PAN = 7; // 0x7
+ }
+
+ public static final class CarIcon.Builder {
+ ctor public CarIcon.Builder(androidx.car.app.model.CarIcon);
+ ctor public CarIcon.Builder(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.car.app.model.CarIcon build();
+ method public androidx.car.app.model.CarIcon.Builder setTint(androidx.car.app.model.CarColor);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIconSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon);
+ method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon, int);
+ method public int getAlignment();
+ method public androidx.car.app.model.CarIcon getIcon();
+ field public static final int ALIGN_BASELINE = 1; // 0x1
+ field public static final int ALIGN_BOTTOM = 0; // 0x0
+ field public static final int ALIGN_CENTER = 2; // 0x2
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarLocation {
+ method public static androidx.car.app.model.CarLocation create(android.location.Location);
+ method public static androidx.car.app.model.CarLocation create(double, double);
+ method public double getLatitude();
+ method public double getLongitude();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public class CarSpan extends android.text.style.CharacterStyle {
+ ctor public CarSpan();
+ method public void updateDrawState(android.text.TextPaint);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarText {
+ method public static androidx.car.app.model.CarText create(CharSequence);
+ method public java.util.List<java.lang.CharSequence!> getVariants();
+ method public boolean isEmpty();
+ method public static boolean isNullOrEmpty(androidx.car.app.model.CarText?);
+ method public CharSequence toCharSequence();
+ }
+
+ @SuppressCompatibility public static final class CarText.Builder {
+ ctor public CarText.Builder(CharSequence);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.CarText.Builder addVariant(CharSequence);
+ method public androidx.car.app.model.CarText build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public final class ClickableSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.ClickableSpan create(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.OnClickDelegate getOnClickDelegate();
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface Content {
+ method public String getContentId();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DateTimeWithZone {
+ method @RequiresApi(26) public static androidx.car.app.model.DateTimeWithZone create(java.time.ZonedDateTime);
+ method public static androidx.car.app.model.DateTimeWithZone create(long, @IntRange(from=0xffff02e0, to=64800) int, String);
+ method public static androidx.car.app.model.DateTimeWithZone create(long, java.util.TimeZone);
+ method public long getTimeSinceEpochMillis();
+ method public int getZoneOffsetSeconds();
+ method public String? getZoneShortName();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Distance {
+ method public static androidx.car.app.model.Distance create(double, int);
+ method public double getDisplayDistance();
+ method public int getDisplayUnit();
+ field public static final int UNIT_FEET = 6; // 0x6
+ field public static final int UNIT_KILOMETERS = 2; // 0x2
+ field public static final int UNIT_KILOMETERS_P1 = 3; // 0x3
+ field public static final int UNIT_METERS = 1; // 0x1
+ field public static final int UNIT_MILES = 4; // 0x4
+ field public static final int UNIT_MILES_P1 = 5; // 0x5
+ field public static final int UNIT_YARDS = 7; // 0x7
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DistanceSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.DistanceSpan create(androidx.car.app.model.Distance);
+ method public androidx.car.app.model.Distance getDistance();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DurationSpan extends androidx.car.app.model.CarSpan {
+ method @RequiresApi(26) public static androidx.car.app.model.DurationSpan create(java.time.Duration);
+ method public static androidx.car.app.model.DurationSpan create(long);
+ method public long getDurationSeconds();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ForegroundCarColorSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.ForegroundCarColorSpan create(androidx.car.app.model.CarColor);
+ method public androidx.car.app.model.CarColor getColor();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridItem implements androidx.car.app.model.Item {
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.Badge? getBadge();
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public int getImageType();
+ method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+ method public androidx.car.app.model.CarText? getText();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ field public static final int IMAGE_TYPE_ICON = 1; // 0x1
+ field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+ }
+
+ public static final class GridItem.Builder {
+ ctor public GridItem.Builder();
+ method public androidx.car.app.model.GridItem build();
+ method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, androidx.car.app.model.Badge);
+ method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int, androidx.car.app.model.Badge);
+ method public androidx.car.app.model.GridItem.Builder setLoading(boolean);
+ method public androidx.car.app.model.GridItem.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.GridItem.Builder setText(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.GridItem.Builder setText(CharSequence);
+ method public androidx.car.app.model.GridItem.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.GridItem.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemImageShape();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemSize();
+ method public androidx.car.app.model.ItemList? getSingleList();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_CIRCLE = 2; // 0x2
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_UNSET = 1; // 0x1
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_LARGE = 4; // 0x4
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_MEDIUM = 2; // 0x2
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_SMALL = 1; // 0x1
+ }
+
+ public static final class GridTemplate.Builder {
+ ctor public GridTemplate.Builder();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.GridTemplate build();
+ method public androidx.car.app.model.GridTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.GridTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemImageShape(@SuppressCompatibility int);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemSize(@SuppressCompatibility int);
+ method public androidx.car.app.model.GridTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.GridTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.GridTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Header {
+ method public java.util.List<androidx.car.app.model.Action!> getEndHeaderActions();
+ method public androidx.car.app.model.Action? getStartHeaderAction();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ public static final class Header.Builder {
+ ctor public Header.Builder();
+ method public androidx.car.app.model.Header.Builder addEndHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Header build();
+ method public androidx.car.app.model.Header.Builder setStartHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Header.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Header.Builder setTitle(CharSequence);
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallback {
+ method public default void onInputSubmitted(String);
+ method public default void onInputTextChanged(String);
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallbackDelegate {
+ method public void sendInputSubmitted(String, androidx.car.app.OnDoneCallback);
+ method public void sendInputTextChanged(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface Item {
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ItemList {
+ method public java.util.List<androidx.car.app.model.Item!> getItems();
+ method public androidx.car.app.model.CarText? getNoItemsMessage();
+ method public androidx.car.app.model.OnItemVisibilityChangedDelegate? getOnItemVisibilityChangedDelegate();
+ method public androidx.car.app.model.OnSelectedDelegate? getOnSelectedDelegate();
+ method public int getSelectedIndex();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder toBuilder();
+ }
+
+ public static final class ItemList.Builder {
+ ctor public ItemList.Builder();
+ method public androidx.car.app.model.ItemList.Builder addItem(androidx.car.app.model.Item);
+ method public androidx.car.app.model.ItemList build();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder clearItems();
+ method public androidx.car.app.model.ItemList.Builder setNoItemsMessage(CharSequence);
+ method public androidx.car.app.model.ItemList.Builder setOnItemsVisibilityChangedListener(androidx.car.app.model.ItemList.OnItemVisibilityChangedListener);
+ method public androidx.car.app.model.ItemList.Builder setOnSelectedListener(androidx.car.app.model.ItemList.OnSelectedListener);
+ method public androidx.car.app.model.ItemList.Builder setSelectedIndex(@IntRange(from=0) int);
+ }
+
+ public static interface ItemList.OnItemVisibilityChangedListener {
+ method public void onItemVisibilityChanged(int, int);
+ }
+
+ public static interface ItemList.OnSelectedListener {
+ method public void onSelected(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ListTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public java.util.List<androidx.car.app.model.SectionedItemList!> getSectionedLists();
+ method public androidx.car.app.model.ItemList? getSingleList();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder toBuilder();
+ }
+
+ public static final class ListTemplate.Builder {
+ ctor public ListTemplate.Builder();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.ListTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.ListTemplate.Builder addSectionedList(androidx.car.app.model.SectionedItemList);
+ method public androidx.car.app.model.ListTemplate build();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder clearSectionedLists();
+ method public androidx.car.app.model.ListTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.ListTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.ListTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.ListTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.ListTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class LongMessageTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.CarText getMessage();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public static final class LongMessageTemplate.Builder {
+ ctor public LongMessageTemplate.Builder(CharSequence);
+ method public androidx.car.app.model.LongMessageTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.LongMessageTemplate build();
+ method public androidx.car.app.model.LongMessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.LongMessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.LongMessageTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageTemplate implements androidx.car.app.model.Template {
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.CarText? getDebugMessage();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public androidx.car.app.model.CarText getMessage();
+ method public androidx.car.app.model.CarText? getTitle();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public boolean isLoading();
+ }
+
+ public static final class MessageTemplate.Builder {
+ ctor public MessageTemplate.Builder(androidx.car.app.model.CarText);
+ ctor public MessageTemplate.Builder(CharSequence);
+ method public androidx.car.app.model.MessageTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.MessageTemplate build();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(String);
+ method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(Throwable);
+ method public androidx.car.app.model.MessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.MessageTemplate.Builder setIcon(androidx.car.app.model.CarIcon);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.MessageTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Metadata {
+ method public androidx.car.app.model.Place? getPlace();
+ field public static final androidx.car.app.model.Metadata EMPTY_METADATA;
+ }
+
+ public static final class Metadata.Builder {
+ ctor public Metadata.Builder();
+ ctor public Metadata.Builder(androidx.car.app.model.Metadata);
+ method public androidx.car.app.model.Metadata build();
+ method public androidx.car.app.model.Metadata.Builder setPlace(androidx.car.app.model.Place);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnCheckedChangeDelegate {
+ method public void sendCheckedChange(boolean, androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnClickDelegate {
+ method public boolean isParkedOnly();
+ method public void sendClick(androidx.car.app.OnDoneCallback);
+ }
+
+ public interface OnClickListener {
+ method public void onClick();
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshDelegate {
+ method public void sendContentRefreshRequested(androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshListener {
+ method public void onContentRefreshRequested();
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnItemVisibilityChangedDelegate {
+ method public void sendItemVisibilityChanged(int, int, androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnSelectedDelegate {
+ method public void sendSelected(int, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Pane {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.CarIcon? getImage();
+ method public java.util.List<androidx.car.app.model.Row!> getRows();
+ method public boolean isLoading();
+ }
+
+ public static final class Pane.Builder {
+ ctor public Pane.Builder();
+ method public androidx.car.app.model.Pane.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Pane.Builder addRow(androidx.car.app.model.Row);
+ method public androidx.car.app.model.Pane build();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Pane.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Pane.Builder setLoading(boolean);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PaneTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.Pane getPane();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ public static final class PaneTemplate.Builder {
+ ctor public PaneTemplate.Builder(androidx.car.app.model.Pane);
+ method public androidx.car.app.model.PaneTemplate build();
+ method public androidx.car.app.model.PaneTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.PaneTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.PaneTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ParkedOnlyOnClickListener implements androidx.car.app.model.OnClickListener {
+ method public static androidx.car.app.model.ParkedOnlyOnClickListener create(androidx.car.app.model.OnClickListener);
+ method public void onClick();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Place {
+ method public androidx.car.app.model.CarLocation getLocation();
+ method public androidx.car.app.model.PlaceMarker? getMarker();
+ }
+
+ public static final class Place.Builder {
+ ctor public Place.Builder(androidx.car.app.model.CarLocation);
+ ctor public Place.Builder(androidx.car.app.model.Place);
+ method public androidx.car.app.model.Place build();
+ method public androidx.car.app.model.Place.Builder setMarker(androidx.car.app.model.PlaceMarker);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListMapTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Place? getAnchor();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isCurrentLocationEnabled();
+ method public boolean isLoading();
+ }
+
+ public static final class PlaceListMapTemplate.Builder {
+ ctor public PlaceListMapTemplate.Builder();
+ method public androidx.car.app.model.PlaceListMapTemplate build();
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setAnchor(androidx.car.app.model.Place);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setCurrentLocationEnabled(boolean);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setLoading(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.PlaceListMapTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceMarker {
+ method public androidx.car.app.model.CarColor? getColor();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public int getIconType();
+ method public androidx.car.app.model.CarText? getLabel();
+ field public static final int TYPE_ICON = 0; // 0x0
+ field public static final int TYPE_IMAGE = 1; // 0x1
+ }
+
+ public static final class PlaceMarker.Builder {
+ ctor public PlaceMarker.Builder();
+ method public androidx.car.app.model.PlaceMarker build();
+ method public androidx.car.app.model.PlaceMarker.Builder setColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.model.PlaceMarker.Builder setIcon(androidx.car.app.model.CarIcon, int);
+ method public androidx.car.app.model.PlaceMarker.Builder setLabel(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Row implements androidx.car.app.model.Item {
+ method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public androidx.car.app.model.Metadata? getMetadata();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public int getNumericDecoration();
+ method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+ method public int getRowImageType();
+ method public java.util.List<androidx.car.app.model.CarText!> getTexts();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public androidx.car.app.model.Toggle? getToggle();
+ method public boolean isBrowsable();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+ method public androidx.car.app.model.Row row();
+ method public CharSequence yourBoat();
+ field public static final int IMAGE_TYPE_ICON = 4; // 0x4
+ field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+ field public static final int IMAGE_TYPE_SMALL = 1; // 0x1
+ field public static final int NO_DECORATION = -1; // 0xffffffff
+ }
+
+ public static final class Row.Builder {
+ ctor public Row.Builder();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Row.Builder addText(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Row.Builder addText(CharSequence);
+ method public androidx.car.app.model.Row build();
+ method public androidx.car.app.model.Row.Builder setBrowsable(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Row.Builder setEnabled(boolean);
+ method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon, int);
+ method public androidx.car.app.model.Row.Builder setMetadata(androidx.car.app.model.Metadata);
+ method @IntRange(from=0) @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder setNumericDecoration(int);
+ method public androidx.car.app.model.Row.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.Row.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Row.Builder setTitle(CharSequence);
+ method public androidx.car.app.model.Row.Builder setToggle(androidx.car.app.model.Toggle);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface SearchCallbackDelegate {
+ method public void sendSearchSubmitted(String, androidx.car.app.OnDoneCallback);
+ method public void sendSearchTextChanged(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SearchTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public String? getInitialSearchText();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method public androidx.car.app.model.SearchCallbackDelegate getSearchCallbackDelegate();
+ method public String? getSearchHint();
+ method public boolean isLoading();
+ method public boolean isShowKeyboardByDefault();
+ }
+
+ public static final class SearchTemplate.Builder {
+ ctor public SearchTemplate.Builder(androidx.car.app.model.SearchTemplate.SearchCallback);
+ method public androidx.car.app.model.SearchTemplate build();
+ method public androidx.car.app.model.SearchTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.SearchTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.SearchTemplate.Builder setInitialSearchText(String);
+ method public androidx.car.app.model.SearchTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.SearchTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.SearchTemplate.Builder setSearchHint(String);
+ method public androidx.car.app.model.SearchTemplate.Builder setShowKeyboardByDefault(boolean);
+ }
+
+ public static interface SearchTemplate.SearchCallback {
+ method public default void onSearchSubmitted(String);
+ method public default void onSearchTextChanged(String);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SectionedItemList {
+ method public static androidx.car.app.model.SectionedItemList create(androidx.car.app.model.ItemList, CharSequence);
+ method public androidx.car.app.model.CarText getHeader();
+ method public androidx.car.app.model.ItemList getItemList();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public final class Tab implements androidx.car.app.model.Content {
+ method public String getContentId();
+ method public androidx.car.app.model.CarIcon getIcon();
+ method public androidx.car.app.model.CarText getTitle();
+ }
+
+ public static final class Tab.Builder {
+ ctor public Tab.Builder();
+ ctor public Tab.Builder(androidx.car.app.model.Tab);
+ method public androidx.car.app.model.Tab build();
+ method public androidx.car.app.model.Tab.Builder setContentId(String);
+ method public androidx.car.app.model.Tab.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Tab.Builder setTitle(CharSequence);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface TabCallbackDelegate {
+ method public void sendTabSelected(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabContents implements androidx.car.app.model.Content {
+ method public String getContentId();
+ method public androidx.car.app.model.Template getTemplate();
+ field public static final String CONTENT_ID = "TAB_CONTENTS_CONTENT_ID";
+ }
+
+ public static final class TabContents.Builder {
+ ctor public TabContents.Builder(androidx.car.app.model.Template);
+ method public androidx.car.app.model.TabContents build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabTemplate implements androidx.car.app.model.Template {
+ method public String getActiveTabContentId();
+ method public androidx.car.app.model.Action getHeaderAction();
+ method public androidx.car.app.model.TabCallbackDelegate getTabCallbackDelegate();
+ method public androidx.car.app.model.TabContents getTabContents();
+ method public java.util.List<androidx.car.app.model.Tab!> getTabs();
+ method public boolean isLoading();
+ }
+
+ public static final class TabTemplate.Builder {
+ ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate);
+ ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate.TabCallback);
+ method public androidx.car.app.model.TabTemplate.Builder addTab(androidx.car.app.model.Tab);
+ method public androidx.car.app.model.TabTemplate build();
+ method public androidx.car.app.model.TabTemplate.Builder setActiveTabContentId(String);
+ method public androidx.car.app.model.TabTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.TabTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.TabTemplate.Builder setTabContents(androidx.car.app.model.TabContents);
+ }
+
+ public static interface TabTemplate.TabCallback {
+ method public default void onTabSelected(String);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface Template {
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateInfo {
+ ctor public TemplateInfo(Class<? extends androidx.car.app.model.Template>, String);
+ method public Class<? extends androidx.car.app.model.Template> getTemplateClass();
+ method public String getTemplateId();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateWrapper {
+ method public static androidx.car.app.model.TemplateWrapper copyOf(androidx.car.app.model.TemplateWrapper);
+ method public int getCurrentTaskStep();
+ method public String getId();
+ method public androidx.car.app.model.Template getTemplate();
+ method public java.util.List<androidx.car.app.model.TemplateInfo!> getTemplateInfosForScreenStack();
+ method public boolean isRefresh();
+ method public void setCurrentTaskStep(int);
+ method public void setId(String);
+ method public void setRefresh(boolean);
+ method public void setTemplate(androidx.car.app.model.Template);
+ method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template);
+ method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template, String);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Toggle {
+ method public androidx.car.app.model.OnCheckedChangeDelegate getOnCheckedChangeDelegate();
+ method public boolean isChecked();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+ }
+
+ public static final class Toggle.Builder {
+ ctor public Toggle.Builder(androidx.car.app.model.Toggle.OnCheckedChangeListener);
+ method public androidx.car.app.model.Toggle build();
+ method public androidx.car.app.model.Toggle.Builder setChecked(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Toggle.Builder setEnabled(boolean);
+ }
+
+ public static interface Toggle.OnCheckedChangeListener {
+ method public void onCheckedChange(boolean);
+ }
+
+}
+
+package androidx.car.app.model.signin {
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class InputSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ 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 public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
+ method public int getInputType();
+ method public int getKeyboardType();
+ method public boolean isShowKeyboardByDefault();
+ field public static final int INPUT_TYPE_DEFAULT = 1; // 0x1
+ field public static final int INPUT_TYPE_PASSWORD = 2; // 0x2
+ field public static final int KEYBOARD_DEFAULT = 1; // 0x1
+ field public static final int KEYBOARD_EMAIL = 2; // 0x2
+ field public static final int KEYBOARD_NUMBER = 4; // 0x4
+ field public static final int KEYBOARD_PHONE = 3; // 0x3
+ }
+
+ public static final class InputSignInMethod.Builder {
+ 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);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setHint(CharSequence);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setInputType(int);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setKeyboardType(int);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setShowKeyboardByDefault(boolean);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class PinSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ ctor public PinSignInMethod(CharSequence);
+ method public androidx.car.app.model.CarText getPinCode();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class ProviderSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ ctor public ProviderSignInMethod(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Action getAction();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(4) public final class QRCodeSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ ctor public QRCodeSignInMethod(android.net.Uri);
+ method public android.net.Uri getUri();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class SignInTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.CarText? getAdditionalText();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.CarText? getInstructions();
+ method public androidx.car.app.model.signin.SignInTemplate.SignInMethod getSignInMethod();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public static final class SignInTemplate.Builder {
+ ctor public SignInTemplate.Builder(androidx.car.app.model.signin.SignInTemplate.SignInMethod);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.signin.SignInTemplate build();
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setAdditionalText(CharSequence);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setInstructions(CharSequence);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setTitle(CharSequence);
+ }
+
+ public static interface SignInTemplate.SignInMethod {
+ }
+
+}
+
+package androidx.car.app.navigation {
+
+ public class NavigationManager implements androidx.car.app.managers.Manager {
+ method @MainThread public void clearNavigationManagerCallback();
+ method @MainThread public void navigationEnded();
+ method @MainThread public void navigationStarted();
+ method @MainThread public void setNavigationManagerCallback(androidx.car.app.navigation.NavigationManagerCallback);
+ method @MainThread public void setNavigationManagerCallback(java.util.concurrent.Executor, androidx.car.app.navigation.NavigationManagerCallback);
+ method @MainThread public void updateTrip(androidx.car.app.navigation.model.Trip);
+ }
+
+ public interface NavigationManagerCallback {
+ method public default void onAutoDriveEnabled();
+ method public default void onStopNavigation();
+ }
+
+}
+
+package androidx.car.app.navigation.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Destination {
+ method public androidx.car.app.model.CarText? getAddress();
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public androidx.car.app.model.CarText? getName();
+ }
+
+ public static final class Destination.Builder {
+ ctor public Destination.Builder();
+ method public androidx.car.app.navigation.model.Destination build();
+ method public androidx.car.app.navigation.model.Destination.Builder setAddress(CharSequence);
+ method public androidx.car.app.navigation.model.Destination.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.Destination.Builder setName(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Lane {
+ method public java.util.List<androidx.car.app.navigation.model.LaneDirection!> getDirections();
+ }
+
+ public static final class Lane.Builder {
+ ctor public Lane.Builder();
+ method public androidx.car.app.navigation.model.Lane.Builder addDirection(androidx.car.app.navigation.model.LaneDirection);
+ method public androidx.car.app.navigation.model.Lane build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class LaneDirection {
+ method public static androidx.car.app.navigation.model.LaneDirection create(int, boolean);
+ method public int getShape();
+ method public boolean isRecommended();
+ field public static final int SHAPE_NORMAL_LEFT = 5; // 0x5
+ field public static final int SHAPE_NORMAL_RIGHT = 6; // 0x6
+ field public static final int SHAPE_SHARP_LEFT = 7; // 0x7
+ field public static final int SHAPE_SHARP_RIGHT = 8; // 0x8
+ field public static final int SHAPE_SLIGHT_LEFT = 3; // 0x3
+ field public static final int SHAPE_SLIGHT_RIGHT = 4; // 0x4
+ field public static final int SHAPE_STRAIGHT = 2; // 0x2
+ field public static final int SHAPE_UNKNOWN = 1; // 0x1
+ field public static final int SHAPE_U_TURN_LEFT = 9; // 0x9
+ field public static final int SHAPE_U_TURN_RIGHT = 10; // 0xa
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Maneuver {
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public int getRoundaboutExitAngle();
+ method public int getRoundaboutExitNumber();
+ method public int getType();
+ field public static final int TYPE_DEPART = 1; // 0x1
+ field public static final int TYPE_DESTINATION = 39; // 0x27
+ field public static final int TYPE_DESTINATION_LEFT = 41; // 0x29
+ field public static final int TYPE_DESTINATION_RIGHT = 42; // 0x2a
+ field public static final int TYPE_DESTINATION_STRAIGHT = 40; // 0x28
+ field public static final int TYPE_FERRY_BOAT = 37; // 0x25
+ field public static final int TYPE_FERRY_BOAT_LEFT = 47; // 0x2f
+ field public static final int TYPE_FERRY_BOAT_RIGHT = 48; // 0x30
+ field public static final int TYPE_FERRY_TRAIN = 38; // 0x26
+ field public static final int TYPE_FERRY_TRAIN_LEFT = 49; // 0x31
+ field public static final int TYPE_FERRY_TRAIN_RIGHT = 50; // 0x32
+ field public static final int TYPE_FORK_LEFT = 25; // 0x19
+ field public static final int TYPE_FORK_RIGHT = 26; // 0x1a
+ field public static final int TYPE_KEEP_LEFT = 3; // 0x3
+ field public static final int TYPE_KEEP_RIGHT = 4; // 0x4
+ field public static final int TYPE_MERGE_LEFT = 27; // 0x1b
+ field public static final int TYPE_MERGE_RIGHT = 28; // 0x1c
+ field public static final int TYPE_MERGE_SIDE_UNSPECIFIED = 29; // 0x1d
+ field public static final int TYPE_NAME_CHANGE = 2; // 0x2
+ field public static final int TYPE_OFF_RAMP_NORMAL_LEFT = 23; // 0x17
+ field public static final int TYPE_OFF_RAMP_NORMAL_RIGHT = 24; // 0x18
+ field public static final int TYPE_OFF_RAMP_SLIGHT_LEFT = 21; // 0x15
+ field public static final int TYPE_OFF_RAMP_SLIGHT_RIGHT = 22; // 0x16
+ field public static final int TYPE_ON_RAMP_NORMAL_LEFT = 15; // 0xf
+ field public static final int TYPE_ON_RAMP_NORMAL_RIGHT = 16; // 0x10
+ field public static final int TYPE_ON_RAMP_SHARP_LEFT = 17; // 0x11
+ field public static final int TYPE_ON_RAMP_SHARP_RIGHT = 18; // 0x12
+ field public static final int TYPE_ON_RAMP_SLIGHT_LEFT = 13; // 0xd
+ field public static final int TYPE_ON_RAMP_SLIGHT_RIGHT = 14; // 0xe
+ field public static final int TYPE_ON_RAMP_U_TURN_LEFT = 19; // 0x13
+ field public static final int TYPE_ON_RAMP_U_TURN_RIGHT = 20; // 0x14
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW = 34; // 0x22
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE = 35; // 0x23
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW = 32; // 0x20
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE = 33; // 0x21
+ field public static final int TYPE_ROUNDABOUT_ENTER_CCW = 45; // 0x2d
+ field public static final int TYPE_ROUNDABOUT_ENTER_CW = 43; // 0x2b
+ field public static final int TYPE_ROUNDABOUT_EXIT_CCW = 46; // 0x2e
+ field public static final int TYPE_ROUNDABOUT_EXIT_CW = 44; // 0x2c
+ field public static final int TYPE_STRAIGHT = 36; // 0x24
+ field public static final int TYPE_TURN_NORMAL_LEFT = 7; // 0x7
+ field public static final int TYPE_TURN_NORMAL_RIGHT = 8; // 0x8
+ field public static final int TYPE_TURN_SHARP_LEFT = 9; // 0x9
+ field public static final int TYPE_TURN_SHARP_RIGHT = 10; // 0xa
+ field public static final int TYPE_TURN_SLIGHT_LEFT = 5; // 0x5
+ field public static final int TYPE_TURN_SLIGHT_RIGHT = 6; // 0x6
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_U_TURN_LEFT = 11; // 0xb
+ field public static final int TYPE_U_TURN_RIGHT = 12; // 0xc
+ }
+
+ public static final class Maneuver.Builder {
+ ctor public Maneuver.Builder(int);
+ method public androidx.car.app.navigation.model.Maneuver build();
+ method public androidx.car.app.navigation.model.Maneuver.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitAngle(@IntRange(from=1, to=360) int);
+ method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitNumber(@IntRange(from=1) int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapController {
+ method public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ }
+
+ public static final class MapController.Builder {
+ ctor public MapController.Builder();
+ method public androidx.car.app.navigation.model.MapController build();
+ method public androidx.car.app.navigation.model.MapController.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.MapController.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Header? getHeader();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method public androidx.car.app.navigation.model.MapController? getMapController();
+ method public androidx.car.app.model.Pane? getPane();
+ }
+
+ public static final class MapTemplate.Builder {
+ ctor public MapTemplate.Builder();
+ method public androidx.car.app.navigation.model.MapTemplate build();
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setHeader(androidx.car.app.model.Header);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setPane(androidx.car.app.model.Pane);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public final class MapWithContentTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Template? getContentTemplate();
+ method public androidx.car.app.navigation.model.MapController? getMapController();
+ method public boolean isLoading();
+ }
+
+ public static final class MapWithContentTemplate.Builder {
+ ctor public MapWithContentTemplate.Builder();
+ method public androidx.car.app.navigation.model.MapWithContentTemplate build();
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setContentTemplate(androidx.car.app.model.Template);
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public androidx.car.app.model.CarText? getText();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ public static final class MessageInfo.Builder {
+ ctor public MessageInfo.Builder(androidx.car.app.model.CarText);
+ ctor public MessageInfo.Builder(CharSequence);
+ method public androidx.car.app.navigation.model.MessageInfo build();
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setText(androidx.car.app.model.CarText);
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setText(CharSequence);
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class NavigationTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.CarColor? getBackgroundColor();
+ method public androidx.car.app.navigation.model.TravelEstimate? getDestinationTravelEstimate();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo? getNavigationInfo();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ method @Deprecated @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.Toggle? getPanModeToggle();
+ }
+
+ public static final class NavigationTemplate.Builder {
+ ctor public NavigationTemplate.Builder();
+ method public androidx.car.app.navigation.model.NavigationTemplate build();
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setDestinationTravelEstimate(androidx.car.app.navigation.model.TravelEstimate);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setNavigationInfo(androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ }
+
+ public static interface NavigationTemplate.NavigationInfo {
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public interface PanModeDelegate {
+ method public void sendPanModeChanged(boolean, androidx.car.app.OnDoneCallback);
+ }
+
+ public interface PanModeListener {
+ method public void onPanModeChanged(boolean);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListNavigationTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+ method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ method @Deprecated public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ }
+
+ public static final class PlaceListNavigationTemplate.Builder {
+ ctor public PlaceListNavigationTemplate.Builder();
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate build();
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+ method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setLoading(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+ method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutePreviewNavigationTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+ method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.model.Action? getNavigateAction();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ method @Deprecated public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ }
+
+ public static final class RoutePreviewNavigationTemplate.Builder {
+ ctor public RoutePreviewNavigationTemplate.Builder();
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate build();
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+ method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setLoading(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setNavigateAction(androidx.car.app.model.Action);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+ method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutingInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+ method public androidx.car.app.model.Distance? getCurrentDistance();
+ method public androidx.car.app.navigation.model.Step? getCurrentStep();
+ method public androidx.car.app.model.CarIcon? getJunctionImage();
+ method public androidx.car.app.navigation.model.Step? getNextStep();
+ method public boolean isLoading();
+ }
+
+ public static final class RoutingInfo.Builder {
+ ctor public RoutingInfo.Builder();
+ method public androidx.car.app.navigation.model.RoutingInfo build();
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setCurrentStep(androidx.car.app.navigation.model.Step, androidx.car.app.model.Distance);
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setJunctionImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setLoading(boolean);
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setNextStep(androidx.car.app.navigation.model.Step);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Step {
+ method public androidx.car.app.model.CarText? getCue();
+ method public java.util.List<androidx.car.app.navigation.model.Lane!> getLanes();
+ method public androidx.car.app.model.CarIcon? getLanesImage();
+ method public androidx.car.app.navigation.model.Maneuver? getManeuver();
+ method public androidx.car.app.model.CarText? getRoad();
+ }
+
+ public static final class Step.Builder {
+ ctor public Step.Builder();
+ ctor public Step.Builder(androidx.car.app.model.CarText);
+ ctor public Step.Builder(CharSequence);
+ method public androidx.car.app.navigation.model.Step.Builder addLane(androidx.car.app.navigation.model.Lane);
+ method public androidx.car.app.navigation.model.Step build();
+ method public androidx.car.app.navigation.model.Step.Builder setCue(CharSequence);
+ method public androidx.car.app.navigation.model.Step.Builder setLanesImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.Step.Builder setManeuver(androidx.car.app.navigation.model.Maneuver);
+ method public androidx.car.app.navigation.model.Step.Builder setRoad(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TravelEstimate {
+ method public androidx.car.app.model.DateTimeWithZone? getArrivalTimeAtDestination();
+ method public androidx.car.app.model.Distance? getRemainingDistance();
+ method public androidx.car.app.model.CarColor? getRemainingDistanceColor();
+ method public androidx.car.app.model.CarColor? getRemainingTimeColor();
+ method public long getRemainingTimeSeconds();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarIcon? getTripIcon();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarText? getTripText();
+ field public static final long REMAINING_TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
+ }
+
+ public static final class TravelEstimate.Builder {
+ ctor public TravelEstimate.Builder(androidx.car.app.model.Distance, androidx.car.app.model.DateTimeWithZone);
+ ctor @RequiresApi(26) public TravelEstimate.Builder(androidx.car.app.model.Distance, java.time.ZonedDateTime);
+ method public androidx.car.app.navigation.model.TravelEstimate build();
+ method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingDistanceColor(androidx.car.app.model.CarColor);
+ method @RequiresApi(26) public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTime(java.time.Duration);
+ method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeSeconds(@IntRange(from=0xffffffff) long);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripIcon(androidx.car.app.model.CarIcon);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripText(androidx.car.app.model.CarText);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Trip {
+ method public androidx.car.app.model.CarText? getCurrentRoad();
+ method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getDestinationTravelEstimates();
+ method public java.util.List<androidx.car.app.navigation.model.Destination!> getDestinations();
+ method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getStepTravelEstimates();
+ method public java.util.List<androidx.car.app.navigation.model.Step!> getSteps();
+ method public boolean isLoading();
+ }
+
+ public static final class Trip.Builder {
+ ctor public Trip.Builder();
+ method public androidx.car.app.navigation.model.Trip.Builder addDestination(androidx.car.app.navigation.model.Destination, androidx.car.app.navigation.model.TravelEstimate);
+ method public androidx.car.app.navigation.model.Trip.Builder addStep(androidx.car.app.navigation.model.Step, androidx.car.app.navigation.model.TravelEstimate);
+ method public androidx.car.app.navigation.model.Trip build();
+ method public androidx.car.app.navigation.model.Trip.Builder setCurrentRoad(CharSequence);
+ method public androidx.car.app.navigation.model.Trip.Builder setLoading(boolean);
+ }
+
+}
+
+package androidx.car.app.notification {
+
+ public final class CarAppExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public CarAppExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public java.util.List<android.app.Notification.Action!> getActions();
+ method public String? getChannelId();
+ method public androidx.car.app.model.CarColor? getColor();
+ method public android.app.PendingIntent? getContentIntent();
+ method public CharSequence? getContentText();
+ method public CharSequence? getContentTitle();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method public int getImportance();
+ method public android.graphics.Bitmap? getLargeIcon();
+ method @DrawableRes public int getSmallIcon();
+ method public static boolean isExtended(android.app.Notification);
+ }
+
+ public static final class CarAppExtender.Builder {
+ ctor public CarAppExtender.Builder();
+ method public androidx.car.app.notification.CarAppExtender.Builder addAction(@DrawableRes int, CharSequence, android.app.PendingIntent);
+ method public androidx.car.app.notification.CarAppExtender build();
+ method public androidx.car.app.notification.CarAppExtender.Builder setChannelId(String);
+ method public androidx.car.app.notification.CarAppExtender.Builder setColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.notification.CarAppExtender.Builder setContentIntent(android.app.PendingIntent);
+ method public androidx.car.app.notification.CarAppExtender.Builder setContentText(CharSequence);
+ method public androidx.car.app.notification.CarAppExtender.Builder setContentTitle(CharSequence);
+ method public androidx.car.app.notification.CarAppExtender.Builder setDeleteIntent(android.app.PendingIntent);
+ method public androidx.car.app.notification.CarAppExtender.Builder setImportance(int);
+ method public androidx.car.app.notification.CarAppExtender.Builder setLargeIcon(android.graphics.Bitmap);
+ method public androidx.car.app.notification.CarAppExtender.Builder setSmallIcon(int);
+ }
+
+ public final class CarNotificationManager {
+ method public boolean areNotificationsEnabled();
+ method public void cancel(int);
+ method public void cancel(String?, int);
+ method public void cancelAll();
+ method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+ method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+ method public void createNotificationChannelGroups(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+ method public void createNotificationChannels(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+ method public void deleteNotificationChannel(String);
+ method public void deleteNotificationChannelGroup(String);
+ method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+ method public static androidx.car.app.notification.CarNotificationManager from(android.content.Context);
+ method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+ method public int getImportance();
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String, String);
+ method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroup(String);
+ method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroups();
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannels();
+ method public void notify(int, androidx.core.app.NotificationCompat.Builder);
+ method public void notify(String?, int, androidx.core.app.NotificationCompat.Builder);
+ }
+
+ public final class CarPendingIntent {
+ method public static android.app.PendingIntent getCarApp(android.content.Context, int, android.content.Intent, int);
+ }
+
+}
+
+package androidx.car.app.serialization {
+
+ public final class Bundleable implements android.os.Parcelable {
+ method public static androidx.car.app.serialization.Bundleable create(Object) throws androidx.car.app.serialization.BundlerException;
+ method public int describeContents();
+ method public Object get() throws androidx.car.app.serialization.BundlerException;
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.car.app.serialization.Bundleable!> CREATOR;
+ }
+
+ public class BundlerException extends java.lang.Exception {
+ ctor public BundlerException(String?);
+ ctor public BundlerException(String?, Throwable);
+ }
+
+}
+
+package androidx.car.app.suggestion {
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public class SuggestionManager implements androidx.car.app.managers.Manager {
+ method @MainThread public void updateSuggestions(java.util.List<androidx.car.app.suggestion.model.Suggestion!>);
+ }
+
+}
+
+package androidx.car.app.suggestion.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Suggestion {
+ method public android.app.PendingIntent? getAction();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public String getIdentifier();
+ method public androidx.car.app.model.CarText? getSubtitle();
+ method public androidx.car.app.model.CarText getTitle();
+ }
+
+ public static final class Suggestion.Builder {
+ ctor public Suggestion.Builder();
+ method public androidx.car.app.suggestion.model.Suggestion build();
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setAction(android.app.PendingIntent);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setIdentifier(String);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setSubtitle(CharSequence);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setTitle(CharSequence);
+ }
+
+}
+
+package androidx.car.app.validation {
+
+ public final class HostValidator {
+ method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getAllowedHosts();
+ method public boolean isValidHost(androidx.car.app.HostInfo);
+ field public static final androidx.car.app.validation.HostValidator ALLOW_ALL_HOSTS_VALIDATOR;
+ field public static final String TEMPLATE_RENDERER_PERMISSION = "android.car.permission.TEMPLATE_RENDERER";
+ }
+
+ public static final class HostValidator.Builder {
+ ctor public HostValidator.Builder(android.content.Context);
+ method public androidx.car.app.validation.HostValidator.Builder addAllowedHost(String, String);
+ method public androidx.car.app.validation.HostValidator.Builder addAllowedHosts(@ArrayRes int);
+ method public androidx.car.app.validation.HostValidator build();
+ }
+
+}
+
+package androidx.car.app.versioning {
+
+ public final class CarAppApiLevels {
+ method public static int getLatest();
+ method public static int getOldest();
+ field public static final int LEVEL_1 = 1; // 0x1
+ field public static final int LEVEL_2 = 2; // 0x2
+ field public static final int LEVEL_3 = 3; // 0x3
+ field public static final int LEVEL_4 = 4; // 0x4
+ field public static final int LEVEL_5 = 5; // 0x5
+ field public static final int LEVEL_6 = 6; // 0x6
+ field public static final int LEVEL_7 = 7; // 0x7
+ }
+
+}
+
diff --git a/car/app/app/api/current.txt b/car/app/app/api/current.txt
index 43d9cf5..73c12de 100644
--- a/car/app/app/api/current.txt
+++ b/car/app/app/api/current.txt
@@ -1055,11 +1055,13 @@
field public static final androidx.car.app.model.CarIcon ALERT;
field public static final androidx.car.app.model.CarIcon APP_ICON;
field public static final androidx.car.app.model.CarIcon BACK;
+ field @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.CarIcon COMPOSE_MESSAGE;
field public static final androidx.car.app.model.CarIcon ERROR;
field @androidx.car.app.annotations.RequiresCarApi(2) public static final androidx.car.app.model.CarIcon PAN;
field public static final int TYPE_ALERT = 4; // 0x4
field public static final int TYPE_APP_ICON = 5; // 0x5
field public static final int TYPE_BACK = 3; // 0x3
+ field public static final int TYPE_COMPOSE_MESSAGE = 8; // 0x8
field public static final int TYPE_CUSTOM = 1; // 0x1
field public static final int TYPE_ERROR = 6; // 0x6
field public static final int TYPE_PAN = 7; // 0x7
diff --git a/car/app/app/api/res-1.4.0-beta01.txt b/car/app/app/api/res-1.4.0-beta01.txt
new file mode 100644
index 0000000..686fc80
--- /dev/null
+++ b/car/app/app/api/res-1.4.0-beta01.txt
@@ -0,0 +1,5 @@
+attr carColorPrimary
+attr carColorPrimaryDark
+attr carColorSecondary
+attr carColorSecondaryDark
+attr carPermissionActivityLayout
diff --git a/car/app/app/api/restricted_1.4.0-beta01.txt b/car/app/app/api/restricted_1.4.0-beta01.txt
new file mode 100644
index 0000000..73c12de
--- /dev/null
+++ b/car/app/app/api/restricted_1.4.0-beta01.txt
@@ -0,0 +1,2210 @@
+// Signature format: 4.0
+package androidx.car.app {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class AppInfo {
+ ctor @VisibleForTesting public AppInfo(int, int, String);
+ method public int getLatestCarAppApiLevel();
+ method public String getLibraryDisplayVersion();
+ method public int getMinCarAppApiLevel();
+ field public static final String MIN_API_LEVEL_METADATA_KEY = "androidx.car.app.minCarApiLevel";
+ }
+
+ public class AppManager implements androidx.car.app.managers.Manager {
+ method @androidx.car.app.annotations.RequiresCarApi(5) public void dismissAlert(int);
+ method public void invalidate();
+ method public void setSurfaceCallback(androidx.car.app.SurfaceCallback?);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public void showAlert(androidx.car.app.model.Alert);
+ method public void showToast(CharSequence, int);
+ }
+
+ public final class CarAppPermission {
+ method public static void checkHasLibraryPermission(android.content.Context, String);
+ method public static void checkHasPermission(android.content.Context, String);
+ field public static final String ACCESS_SURFACE = "androidx.car.app.ACCESS_SURFACE";
+ field public static final String MAP_TEMPLATES = "androidx.car.app.MAP_TEMPLATES";
+ field public static final String NAVIGATION_TEMPLATES = "androidx.car.app.NAVIGATION_TEMPLATES";
+ }
+
+ public abstract class CarAppService extends android.app.Service {
+ ctor public CarAppService();
+ method public abstract androidx.car.app.validation.HostValidator createHostValidator();
+ method @CallSuper public final void dump(java.io.FileDescriptor, java.io.PrintWriter, String![]?);
+ method @Deprecated public final androidx.car.app.Session? getCurrentSession();
+ method public final androidx.car.app.HostInfo? getHostInfo();
+ method public final androidx.car.app.Session? getSession(androidx.car.app.SessionInfo);
+ method @CallSuper public final android.os.IBinder onBind(android.content.Intent);
+ method public androidx.car.app.Session onCreateSession();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.Session onCreateSession(androidx.car.app.SessionInfo);
+ method public final boolean onUnbind(android.content.Intent);
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_CALLING_APP = "androidx.car.app.category.CALLING";
+ field @Deprecated public static final String CATEGORY_CHARGING_APP = "androidx.car.app.category.CHARGING";
+ field @androidx.car.app.annotations.RequiresCarApi(6) public static final String CATEGORY_FEATURE_CLUSTER = "androidx.car.app.category.FEATURE_CLUSTER";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_IOT_APP = "androidx.car.app.category.IOT";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_MESSAGING_APP = "androidx.car.app.category.MESSAGING";
+ field public static final String CATEGORY_NAVIGATION_APP = "androidx.car.app.category.NAVIGATION";
+ field @Deprecated public static final String CATEGORY_PARKING_APP = "androidx.car.app.category.PARKING";
+ field public static final String CATEGORY_POI_APP = "androidx.car.app.category.POI";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_SETTINGS_APP = "androidx.car.app.category.SETTINGS";
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final String CATEGORY_WEATHER_APP = "androidx.car.app.category.WEATHER";
+ field public static final String SERVICE_INTERFACE = "androidx.car.app.CarAppService";
+ }
+
+ public class CarContext extends android.content.ContextWrapper {
+ method public void finishCarApp();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public android.content.ComponentName? getCallingComponent();
+ method public int getCarAppApiLevel();
+ method public <T> T getCarService(Class<T!>);
+ method public Object getCarService(String);
+ method public String getCarServiceName(Class<?>);
+ method public androidx.car.app.HostInfo? getHostInfo();
+ method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+ method public boolean isDarkMode();
+ method public void requestPermissions(java.util.List<java.lang.String!>, androidx.car.app.OnRequestPermissionsListener);
+ method public void requestPermissions(java.util.List<java.lang.String!>, java.util.concurrent.Executor, androidx.car.app.OnRequestPermissionsListener);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public void setCarAppResult(int, android.content.Intent?);
+ method public void startCarApp(android.content.Intent);
+ method @Deprecated public static void startCarApp(android.content.Intent, android.content.Intent);
+ field public static final String ACTION_NAVIGATE = "androidx.car.app.action.NAVIGATE";
+ field public static final String APP_SERVICE = "app";
+ field public static final String CAR_SERVICE = "car";
+ field @androidx.car.app.annotations.RequiresCarApi(2) public static final String CONSTRAINT_SERVICE = "constraints";
+ field public static final String EXTRA_START_CAR_APP_BINDER_KEY = "androidx.car.app.extra.START_CAR_APP_BINDER_KEY";
+ field @androidx.car.app.annotations.RequiresCarApi(3) public static final String HARDWARE_SERVICE = "hardware";
+ field public static final String NAVIGATION_SERVICE = "navigation";
+ field public static final String SCREEN_SERVICE = "screen";
+ field public static final String SUGGESTION_SERVICE = "suggestion";
+ }
+
+ public final class CarToast {
+ method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, @StringRes int, int);
+ method public static androidx.car.app.CarToast makeText(androidx.car.app.CarContext, CharSequence, int);
+ method public void setDuration(int);
+ method public void setText(@StringRes int);
+ method public void setText(CharSequence);
+ method public void show();
+ field public static final int LENGTH_LONG = 1; // 0x1
+ field public static final int LENGTH_SHORT = 0; // 0x0
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class FailureResponse {
+ ctor public FailureResponse(Throwable);
+ method public int getErrorType();
+ method public String getStackTrace();
+ field public static final int BUNDLER_EXCEPTION = 1; // 0x1
+ field public static final int ILLEGAL_STATE_EXCEPTION = 2; // 0x2
+ field public static final int INVALID_PARAMETER_EXCEPTION = 3; // 0x3
+ field public static final int REMOTE_EXCEPTION = 6; // 0x6
+ field public static final int RUNTIME_EXCEPTION = 5; // 0x5
+ field public static final int SECURITY_EXCEPTION = 4; // 0x4
+ field public static final int UNKNOWN_ERROR = 0; // 0x0
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class HandshakeInfo {
+ ctor public HandshakeInfo(String, int);
+ method public int getHostCarAppApiLevel();
+ method public String getHostPackageName();
+ }
+
+ public final class HostException extends java.lang.RuntimeException {
+ ctor public HostException(String);
+ ctor public HostException(String, Throwable);
+ ctor public HostException(Throwable);
+ }
+
+ public final class HostInfo {
+ ctor public HostInfo(String, int);
+ method public String getPackageName();
+ method public int getUid();
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnDoneCallback {
+ method public default void onFailure(androidx.car.app.serialization.Bundleable);
+ method public default void onSuccess(androidx.car.app.serialization.Bundleable?);
+ }
+
+ public interface OnRequestPermissionsListener {
+ method public void onRequestPermissionsResult(java.util.List<java.lang.String!>, java.util.List<java.lang.String!>);
+ }
+
+ public interface OnScreenResultListener {
+ method public void onScreenResult(Object?);
+ }
+
+ public abstract class Screen implements androidx.lifecycle.LifecycleOwner {
+ ctor protected Screen(androidx.car.app.CarContext);
+ method public final void finish();
+ method public final androidx.car.app.CarContext getCarContext();
+ method public final androidx.lifecycle.Lifecycle getLifecycle();
+ method public String? getMarker();
+ method public final androidx.car.app.ScreenManager getScreenManager();
+ method public final void invalidate();
+ method public abstract androidx.car.app.model.Template onGetTemplate();
+ method public void setMarker(String?);
+ method public void setResult(Object?);
+ }
+
+ @MainThread public class ScreenManager implements androidx.car.app.managers.Manager {
+ method public java.util.Collection<androidx.car.app.Screen!> getScreenStack();
+ method public int getStackSize();
+ method public androidx.car.app.Screen getTop();
+ method public void pop();
+ method public void popTo(String);
+ method public void popToRoot();
+ method public void push(androidx.car.app.Screen);
+ method public void pushForResult(androidx.car.app.Screen, androidx.car.app.OnScreenResultListener);
+ method public void remove(androidx.car.app.Screen);
+ }
+
+ public abstract class Session implements androidx.lifecycle.LifecycleOwner {
+ ctor public Session();
+ method public final androidx.car.app.CarContext getCarContext();
+ method public androidx.lifecycle.Lifecycle getLifecycle();
+ method public void onCarConfigurationChanged(android.content.res.Configuration);
+ method public abstract androidx.car.app.Screen onCreateScreen(android.content.Intent);
+ method public void onNewIntent(android.content.Intent);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class SessionInfo {
+ ctor public SessionInfo(int, String);
+ method public int getDisplayType();
+ method public String getSessionId();
+ method public java.util.Set<java.lang.Class<? extends androidx.car.app.model.Template>!>? getSupportedTemplates(int);
+ field public static final androidx.car.app.SessionInfo DEFAULT_SESSION_INFO;
+ field public static final int DISPLAY_TYPE_CLUSTER = 1; // 0x1
+ field public static final int DISPLAY_TYPE_MAIN = 0; // 0x0
+ }
+
+ public class SessionInfoIntentEncoder {
+ method public static boolean containsSessionInfo(android.content.Intent);
+ method public static androidx.car.app.SessionInfo decode(android.content.Intent);
+ method public static void encode(androidx.car.app.SessionInfo, android.content.Intent);
+ }
+
+ public interface SurfaceCallback {
+ method @androidx.car.app.annotations.RequiresCarApi(5) public default void onClick(float, float);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public default void onFling(float, float);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScale(float, float, float);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public default void onScroll(float, float);
+ method public default void onStableAreaChanged(android.graphics.Rect);
+ method public default void onSurfaceAvailable(androidx.car.app.SurfaceContainer);
+ method public default void onSurfaceDestroyed(androidx.car.app.SurfaceContainer);
+ method public default void onVisibleAreaChanged(android.graphics.Rect);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SurfaceContainer {
+ ctor public SurfaceContainer(android.view.Surface?, int, int, int);
+ method public int getDpi();
+ method public int getHeight();
+ method public android.view.Surface? getSurface();
+ method public int getWidth();
+ }
+
+}
+
+package androidx.car.app.annotations {
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.PARAMETER}) public @interface CarProtocol {
+ }
+
+ @SuppressCompatibility @RequiresOptIn @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface ExperimentalCarApi {
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD}) public @interface RequiresCarApi {
+ method public abstract int value();
+ }
+
+}
+
+package androidx.car.app.connection {
+
+ public final class CarConnection {
+ ctor @MainThread public CarConnection(android.content.Context);
+ method public androidx.lifecycle.LiveData<java.lang.Integer!> getType();
+ field public static final String ACTION_CAR_CONNECTION_UPDATED = "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED";
+ field public static final String CAR_CONNECTION_STATE = "CarConnectionState";
+ field public static final int CONNECTION_TYPE_NATIVE = 1; // 0x1
+ field public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; // 0x0
+ field public static final int CONNECTION_TYPE_PROJECTION = 2; // 0x2
+ }
+
+}
+
+package androidx.car.app.constraints {
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public class ConstraintManager implements androidx.car.app.managers.Manager {
+ method public int getContentLimit(int);
+ method @androidx.car.app.annotations.RequiresCarApi(6) public boolean isAppDrivenRefreshEnabled();
+ field public static final int CONTENT_LIMIT_TYPE_GRID = 1; // 0x1
+ field public static final int CONTENT_LIMIT_TYPE_LIST = 0; // 0x0
+ field public static final int CONTENT_LIMIT_TYPE_PANE = 4; // 0x4
+ field public static final int CONTENT_LIMIT_TYPE_PLACE_LIST = 2; // 0x2
+ field public static final int CONTENT_LIMIT_TYPE_ROUTE_LIST = 3; // 0x3
+ }
+
+}
+
+package androidx.car.app.hardware {
+
+ @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarHardwareManager extends androidx.car.app.managers.Manager {
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public default androidx.car.app.hardware.climate.CarClimate getCarClimate();
+ method public default androidx.car.app.hardware.info.CarInfo getCarInfo();
+ method public default androidx.car.app.hardware.info.CarSensors getCarSensors();
+ }
+
+}
+
+package androidx.car.app.hardware.climate {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CabinTemperatureProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!> getCarZoneSetsToCabinCelsiusTemperatureRanges();
+ method public float getCelsiusSupportedIncrement();
+ method public float getFahrenheitSupportedIncrement();
+ method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxCelsiusRange();
+ method public android.util.Pair<java.lang.Float!,java.lang.Float!> getSupportedMinMaxFahrenheitRange();
+ method public boolean hasCarZoneSetsToCabinCelsiusTemperatureRanges();
+ method public boolean hasCelsiusSupportedIncrement();
+ method public boolean hasFahrenheitSupportedIncrement();
+ method public boolean hasSupportedMinMaxCelsiusRange();
+ method public boolean hasSupportedMinMaxFahrenheitRange();
+ }
+
+ public static final class CabinTemperatureProfile.Builder {
+ ctor public CabinTemperatureProfile.Builder();
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile build();
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCarZoneSetsToCabinCelsiusTemperatureRanges(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Float!,java.lang.Float!>!>);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setCelsiusSupportedIncrement(float);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setFahrenheitSupportedIncrement(float);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxCelsiusRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+ method public androidx.car.app.hardware.climate.CabinTemperatureProfile.Builder setSupportedMinMaxFahrenheitRange(android.util.Pair<java.lang.Float!,java.lang.Float!>);
+ }
+
+ @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimate {
+ method public void fetchClimateProfile(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateProfileRequest, androidx.car.app.hardware.climate.CarClimateProfileCallback);
+ method public void registerClimateStateCallback(java.util.concurrent.Executor, androidx.car.app.hardware.climate.RegisterClimateStateRequest, androidx.car.app.hardware.climate.CarClimateStateCallback);
+ method public <E> void setClimateState(java.util.concurrent.Executor, androidx.car.app.hardware.climate.ClimateStateRequest<E!>, androidx.car.app.hardware.common.CarSetOperationStatusCallback);
+ method public void unregisterClimateStateCallback(androidx.car.app.hardware.climate.CarClimateStateCallback);
+ }
+
+ @SuppressCompatibility @MainThread @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarClimateFeature {
+ method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+ method public int getFeature();
+ }
+
+ public static final class CarClimateFeature.Builder {
+ ctor public CarClimateFeature.Builder(int);
+ method public androidx.car.app.hardware.climate.CarClimateFeature.Builder addCarZones(androidx.car.app.hardware.common.CarZone!...);
+ method public androidx.car.app.hardware.climate.CarClimateFeature build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateProfileCallback {
+ method public default void onCabinTemperatureProfileAvailable(androidx.car.app.hardware.climate.CabinTemperatureProfile);
+ method public default void onCarZoneMappingInfoProfileAvailable(androidx.car.app.hardware.climate.CarZoneMappingInfoProfile);
+ method public default void onDefrosterProfileAvailable(androidx.car.app.hardware.climate.DefrosterProfile);
+ method public default void onElectricDefrosterProfileAvailable(androidx.car.app.hardware.climate.ElectricDefrosterProfile);
+ method public default void onFanDirectionProfileAvailable(androidx.car.app.hardware.climate.FanDirectionProfile);
+ method public default void onFanSpeedLevelProfileAvailable(androidx.car.app.hardware.climate.FanSpeedLevelProfile);
+ method public default void onHvacAcProfileAvailable(androidx.car.app.hardware.climate.HvacAcProfile);
+ method public default void onHvacAutoModeProfileAvailable(androidx.car.app.hardware.climate.HvacAutoModeProfile);
+ method public default void onHvacAutoRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacAutoRecirculationProfile);
+ method public default void onHvacDualModeProfileAvailable(androidx.car.app.hardware.climate.HvacDualModeProfile);
+ method public default void onHvacMaxAcModeProfileAvailable(androidx.car.app.hardware.climate.HvacMaxAcModeProfile);
+ method public default void onHvacPowerProfileAvailable(androidx.car.app.hardware.climate.HvacPowerProfile);
+ method public default void onHvacRecirculationProfileAvailable(androidx.car.app.hardware.climate.HvacRecirculationProfile);
+ method public default void onMaxDefrosterProfileAvailable(androidx.car.app.hardware.climate.MaxDefrosterProfile);
+ method public default void onSeatTemperatureLevelProfileAvailable(androidx.car.app.hardware.climate.SeatTemperatureProfile);
+ method public default void onSeatVentilationLevelProfileAvailable(androidx.car.app.hardware.climate.SeatVentilationProfile);
+ method public default void onSteeringWheelHeatProfileAvailable(androidx.car.app.hardware.climate.SteeringWheelHeatProfile);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarClimateStateCallback {
+ method public default void onCabinTemperatureStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public default void onDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onElectricDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onFanDirectionStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onFanSpeedLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onHvacAcStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacAutoModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacAutoRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacDualModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacMaxAcModeStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacPowerStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onHvacRecirculationStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onMaxDefrosterStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public default void onSeatTemperatureLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onSeatVentilationLevelStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public default void onSteeringWheelHeatStateAvailable(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class CarZoneMappingInfoProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class CarZoneMappingInfoProfile.Builder {
+ ctor public CarZoneMappingInfoProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.CarZoneMappingInfoProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateProfileRequest {
+ method public java.util.Set<java.lang.Integer!> getAllClimateProfiles();
+ method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateProfileFeatures();
+ field public static final int FEATURE_CABIN_TEMPERATURE = 4; // 0x4
+ field public static final int FEATURE_CAR_ZONE_MAPPING = 17; // 0x11
+ field public static final int FEATURE_FAN_DIRECTION = 6; // 0x6
+ field public static final int FEATURE_FAN_SPEED = 5; // 0x5
+ field public static final int FEATURE_HVAC_AC = 2; // 0x2
+ field public static final int FEATURE_HVAC_AUTO_MODE = 12; // 0xc
+ field public static final int FEATURE_HVAC_AUTO_RECIRCULATION = 11; // 0xb
+ field public static final int FEATURE_HVAC_DEFROSTER = 14; // 0xe
+ field public static final int FEATURE_HVAC_DUAL_MODE = 13; // 0xd
+ field public static final int FEATURE_HVAC_ELECTRIC_DEFROSTER = 16; // 0x10
+ field public static final int FEATURE_HVAC_MAX_AC = 3; // 0x3
+ field public static final int FEATURE_HVAC_MAX_DEFROSTER = 15; // 0xf
+ field public static final int FEATURE_HVAC_POWER = 1; // 0x1
+ field public static final int FEATURE_HVAC_RECIRCULATION = 10; // 0xa
+ field public static final int FEATURE_SEAT_TEMPERATURE_LEVEL = 7; // 0x7
+ field public static final int FEATURE_SEAT_VENTILATION_LEVEL = 8; // 0x8
+ field public static final int FEATURE_STEERING_WHEEL_HEAT = 9; // 0x9
+ }
+
+ public static final class ClimateProfileRequest.Builder {
+ ctor public ClimateProfileRequest.Builder();
+ method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder addClimateProfileFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+ method public androidx.car.app.hardware.climate.ClimateProfileRequest build();
+ method public androidx.car.app.hardware.climate.ClimateProfileRequest.Builder setAllClimateProfiles();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class ClimateStateRequest<T> {
+ method public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+ method public int getRequestedFeature();
+ method public T getRequestedValue();
+ }
+
+ public static final class ClimateStateRequest.Builder<T> {
+ ctor public ClimateStateRequest.Builder(int, T!);
+ method public androidx.car.app.hardware.climate.ClimateStateRequest.Builder<T!> addCarZones(androidx.car.app.hardware.common.CarZone);
+ method public androidx.car.app.hardware.climate.ClimateStateRequest<T!> build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class DefrosterProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class DefrosterProfile.Builder {
+ ctor public DefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.DefrosterProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class ElectricDefrosterProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class ElectricDefrosterProfile.Builder {
+ ctor public ElectricDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.ElectricDefrosterProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanDirectionProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!> getCarZoneSetsToFanDirectionValues();
+ }
+
+ public static final class FanDirectionProfile.Builder {
+ ctor public FanDirectionProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,java.util.Set<java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.FanDirectionProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class FanSpeedLevelProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToFanSpeedLevelRanges();
+ }
+
+ public static final class FanSpeedLevelProfile.Builder {
+ ctor public FanSpeedLevelProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.FanSpeedLevelProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAcProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacAcProfile.Builder {
+ ctor public HvacAcProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacAcProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoModeProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacAutoModeProfile.Builder {
+ ctor public HvacAutoModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacAutoModeProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacAutoRecirculationProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacAutoRecirculationProfile.Builder {
+ ctor public HvacAutoRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacAutoRecirculationProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacDualModeProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacDualModeProfile.Builder {
+ ctor public HvacDualModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacDualModeProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacMaxAcModeProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacMaxAcModeProfile.Builder {
+ ctor public HvacMaxAcModeProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacMaxAcModeProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacPowerProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class HvacPowerProfile.Builder {
+ ctor public HvacPowerProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacPowerProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class HvacRecirculationProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZones();
+ }
+
+ public static final class HvacRecirculationProfile.Builder {
+ ctor public HvacRecirculationProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.HvacRecirculationProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class MaxDefrosterProfile {
+ method public java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!> getSupportedCarZoneSets();
+ }
+
+ public static final class MaxDefrosterProfile.Builder {
+ ctor public MaxDefrosterProfile.Builder(java.util.List<java.util.Set<androidx.car.app.hardware.common.CarZone!>!>);
+ method public androidx.car.app.hardware.climate.MaxDefrosterProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class RegisterClimateStateRequest {
+ method public java.util.List<androidx.car.app.hardware.climate.CarClimateFeature!> getClimateRegisterFeatures();
+ }
+
+ public static final class RegisterClimateStateRequest.Builder {
+ ctor public RegisterClimateStateRequest.Builder(boolean);
+ method public androidx.car.app.hardware.climate.RegisterClimateStateRequest.Builder addClimateRegisterFeatures(androidx.car.app.hardware.climate.CarClimateFeature!...);
+ method public androidx.car.app.hardware.climate.RegisterClimateStateRequest build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatTemperatureProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatTemperatureValues();
+ }
+
+ public static final class SeatTemperatureProfile.Builder {
+ ctor public SeatTemperatureProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.SeatTemperatureProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SeatVentilationProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSeatVentilationValues();
+ }
+
+ public static final class SeatVentilationProfile.Builder {
+ ctor public SeatVentilationProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.SeatVentilationProfile build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public final class SteeringWheelHeatProfile {
+ method public java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!> getCarZoneSetsToSteeringWheelHeatValues();
+ }
+
+ public static final class SteeringWheelHeatProfile.Builder {
+ ctor public SteeringWheelHeatProfile.Builder(java.util.Map<java.util.Set<androidx.car.app.hardware.common.CarZone!>!,android.util.Pair<java.lang.Integer!,java.lang.Integer!>!>);
+ method public androidx.car.app.hardware.climate.SteeringWheelHeatProfile build();
+ }
+
+}
+
+package androidx.car.app.hardware.common {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public interface CarSetOperationStatusCallback {
+ method public default void onSetCarClimateStateCabinTemperature(int);
+ method public default void onSetCarClimateStateDefroster(int);
+ method public default void onSetCarClimateStateElectricDefroster(int);
+ method public default void onSetCarClimateStateFanDirection(int);
+ method public default void onSetCarClimateStateFanSpeedLevel(int);
+ method public default void onSetCarClimateStateHvacAc(int);
+ method public default void onSetCarClimateStateHvacAutoMode(int);
+ method public default void onSetCarClimateStateHvacAutoRecirculation(int);
+ method public default void onSetCarClimateStateHvacDualMode(int);
+ method public default void onSetCarClimateStateHvacMaxAcMode(int);
+ method public default void onSetCarClimateStateHvacPower(int);
+ method public default void onSetCarClimateStateHvacRecirculation(int);
+ method public default void onSetCarClimateStateMaxDefroster(int);
+ method public default void onSetCarClimateStateSeatTemperatureLevel(int);
+ method public default void onSetCarClimateStateSeatVentilationLevel(int);
+ method public default void onSetCarClimateStateSteeringWheelHeat(int);
+ method public static String toString(int);
+ field public static final int OPERATION_STATUS_FEATURE_SETTING_NOT_ALLOWED = 4; // 0x4
+ field public static final int OPERATION_STATUS_FEATURE_TEMPORARILY_UNAVAILABLE = 3; // 0x3
+ field public static final int OPERATION_STATUS_FEATURE_UNIMPLEMENTED = 1; // 0x1
+ field public static final int OPERATION_STATUS_FEATURE_UNSUPPORTED = 2; // 0x2
+ field public static final int OPERATION_STATUS_ILLEGAL_CAR_HARDWARE_STATE = 7; // 0x7
+ field public static final int OPERATION_STATUS_INSUFFICIENT_PERMISSION = 6; // 0x6
+ field public static final int OPERATION_STATUS_SUCCESS = 0; // 0x0
+ field public static final int OPERATION_STATUS_UNSUPPORTED_VALUE = 5; // 0x5
+ field public static final int OPERATION_STATUS_UPDATE_TIMEOUT = 8; // 0x8
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarUnit {
+ method public static String toString(int);
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int IMPERIAL_GALLON = 204; // 0xcc
+ field public static final int KILOMETER = 3; // 0x3
+ field public static final int KILOMETERS_PER_HOUR = 102; // 0x66
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int LITER = 202; // 0xca
+ field public static final int METER = 2; // 0x2
+ field public static final int METERS_PER_SEC = 101; // 0x65
+ field public static final int MILE = 4; // 0x4
+ field public static final int MILES_PER_HOUR = 103; // 0x67
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int MILLILITER = 201; // 0xc9
+ field public static final int MILLIMETER = 1; // 0x1
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public static final int US_GALLON = 203; // 0xcb
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarValue<T> {
+ ctor public CarValue(T?, long, int);
+ ctor @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public CarValue(T?, long, int, java.util.List<androidx.car.app.hardware.common.CarZone!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public java.util.List<androidx.car.app.hardware.common.CarZone!> getCarZones();
+ method public int getStatus();
+ method public long getTimestampMillis();
+ method public T? getValue();
+ field public static final int STATUS_SUCCESS = 1; // 0x1
+ field public static final int STATUS_UNAVAILABLE = 3; // 0x3
+ field public static final int STATUS_UNIMPLEMENTED = 2; // 0x2
+ field public static final int STATUS_UNKNOWN = 0; // 0x0
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(5) public final class CarZone {
+ method public int getColumn();
+ method public int getRow();
+ field public static final int CAR_ZONE_COLUMN_ALL = 16; // 0x10
+ field public static final int CAR_ZONE_COLUMN_CENTER = 48; // 0x30
+ field public static final int CAR_ZONE_COLUMN_DRIVER = 80; // 0x50
+ field public static final int CAR_ZONE_COLUMN_LEFT = 32; // 0x20
+ field public static final int CAR_ZONE_COLUMN_PASSENGER = 96; // 0x60
+ field public static final int CAR_ZONE_COLUMN_RIGHT = 64; // 0x40
+ field public static final androidx.car.app.hardware.common.CarZone CAR_ZONE_GLOBAL;
+ field public static final int CAR_ZONE_ROW_ALL = 0; // 0x0
+ field public static final int CAR_ZONE_ROW_EXCLUDE_FIRST = 4; // 0x4
+ field public static final int CAR_ZONE_ROW_FIRST = 1; // 0x1
+ field public static final int CAR_ZONE_ROW_SECOND = 2; // 0x2
+ field public static final int CAR_ZONE_ROW_THIRD = 3; // 0x3
+ }
+
+ public static final class CarZone.Builder {
+ ctor public CarZone.Builder();
+ method public androidx.car.app.hardware.common.CarZone build();
+ method public androidx.car.app.hardware.common.CarZone.Builder setColumn(int);
+ method public androidx.car.app.hardware.common.CarZone.Builder setRow(int);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public interface OnCarDataAvailableListener<T> {
+ method public void onCarDataAvailable(T);
+ }
+
+}
+
+package androidx.car.app.hardware.info {
+
+ @SuppressCompatibility @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.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getForces();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class CarHardwareLocation {
+ ctor public CarHardwareLocation(androidx.car.app.hardware.common.CarValue<android.location.Location!>);
+ method public androidx.car.app.hardware.common.CarValue<android.location.Location!> getLocation();
+ }
+
+ @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarInfo {
+ method public void addEnergyLevelListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void addEvStatusListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+ method public void addMileageListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+ method public void addSpeedListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+ method public void addTollListener(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+ method public void fetchEnergyProfile(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyProfile!>);
+ method public void fetchModel(java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Model!>);
+ method public void removeEnergyLevelListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EnergyLevel!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public void removeEvStatusListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.EvStatus!>);
+ method public void removeMileageListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Mileage!>);
+ method public void removeSpeedListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Speed!>);
+ method public void removeTollListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.TollCard!>);
+ }
+
+ @MainThread @androidx.car.app.annotations.RequiresCarApi(3) public interface CarSensors {
+ method public void addAccelerometerListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+ method public void addCarHardwareLocationListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+ method public void addCompassListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+ method public void addGyroscopeListener(int, java.util.concurrent.Executor, androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+ method public void removeAccelerometerListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Accelerometer!>);
+ method public void removeCarHardwareLocationListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.CarHardwareLocation!>);
+ method public void removeCompassListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Compass!>);
+ method public void removeGyroscopeListener(androidx.car.app.hardware.common.OnCarDataAvailableListener<androidx.car.app.hardware.info.Gyroscope!>);
+ field public static final int UPDATE_RATE_FASTEST = 3; // 0x3
+ field public static final int UPDATE_RATE_NORMAL = 1; // 0x1
+ field public static final int UPDATE_RATE_UI = 2; // 0x2
+ }
+
+ @SuppressCompatibility @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.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getOrientations();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyLevel {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getBatteryPercent();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEnergyIsLow();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getFuelPercent();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getFuelVolumeDisplayUnit();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRangeRemainingMeters();
+ }
+
+ public static final class EnergyLevel.Builder {
+ ctor public EnergyLevel.Builder();
+ method public androidx.car.app.hardware.info.EnergyLevel build();
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setBatteryPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setEnergyIsLow(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelPercent(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.hardware.info.EnergyLevel.Builder setFuelVolumeDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public androidx.car.app.hardware.info.EnergyLevel.Builder setRangeRemainingMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class EnergyProfile {
+ 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
+ field public static final int EVCONNECTOR_TYPE_GBT = 9; // 0x9
+ field public static final int EVCONNECTOR_TYPE_GBT_DC = 10; // 0xa
+ field public static final int EVCONNECTOR_TYPE_J1772 = 1; // 0x1
+ field public static final int EVCONNECTOR_TYPE_MENNEKES = 2; // 0x2
+ field public static final int EVCONNECTOR_TYPE_OTHER = 101; // 0x65
+ field public static final int EVCONNECTOR_TYPE_SCAME = 11; // 0xb
+ field public static final int EVCONNECTOR_TYPE_TESLA_HPWC = 7; // 0x7
+ field public static final int EVCONNECTOR_TYPE_TESLA_ROADSTER = 6; // 0x6
+ field public static final int EVCONNECTOR_TYPE_TESLA_SUPERCHARGER = 8; // 0x8
+ field public static final int EVCONNECTOR_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int FUEL_TYPE_BIODIESEL = 5; // 0x5
+ field public static final int FUEL_TYPE_CNG = 8; // 0x8
+ field public static final int FUEL_TYPE_DIESEL_1 = 3; // 0x3
+ field public static final int FUEL_TYPE_DIESEL_2 = 4; // 0x4
+ field public static final int FUEL_TYPE_E85 = 6; // 0x6
+ field public static final int FUEL_TYPE_ELECTRIC = 10; // 0xa
+ field public static final int FUEL_TYPE_HYDROGEN = 11; // 0xb
+ field public static final int FUEL_TYPE_LEADED = 2; // 0x2
+ field public static final int FUEL_TYPE_LNG = 9; // 0x9
+ field public static final int FUEL_TYPE_LPG = 7; // 0x7
+ field public static final int FUEL_TYPE_OTHER = 12; // 0xc
+ field public static final int FUEL_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int FUEL_TYPE_UNLEADED = 1; // 0x1
+ }
+
+ 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.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!>!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public class EvStatus {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortConnected();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Boolean!> getEvChargePortOpen();
+ }
+
+ public static final class EvStatus.Builder {
+ ctor public EvStatus.Builder();
+ method public androidx.car.app.hardware.info.EvStatus build();
+ method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortConnected(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ method public androidx.car.app.hardware.info.EvStatus.Builder setEvChargePortOpen(androidx.car.app.hardware.common.CarValue<java.lang.Boolean!>);
+ }
+
+ @SuppressCompatibility @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.util.List<java.lang.Float!>!>);
+ method public androidx.car.app.hardware.common.CarValue<java.util.List<java.lang.Float!>!> getRotations();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Mileage {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getDistanceDisplayUnit();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getOdometerMeters();
+ }
+
+ public static final class Mileage.Builder {
+ ctor public Mileage.Builder();
+ method public androidx.car.app.hardware.info.Mileage build();
+ method public androidx.car.app.hardware.info.Mileage.Builder setDistanceDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ method public androidx.car.app.hardware.info.Mileage.Builder setOdometerMeters(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Model {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getManufacturer();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.String!> getName();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getYear();
+ }
+
+ public static final class Model.Builder {
+ ctor public Model.Builder();
+ method public androidx.car.app.hardware.info.Model build();
+ method public androidx.car.app.hardware.info.Model.Builder setManufacturer(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+ method public androidx.car.app.hardware.info.Model.Builder setName(androidx.car.app.hardware.common.CarValue<java.lang.String!>);
+ method public androidx.car.app.hardware.info.Model.Builder setYear(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class Speed {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getDisplaySpeedMetersPerSecond();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Float!> getRawSpeedMetersPerSecond();
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getSpeedDisplayUnit();
+ }
+
+ public static final class Speed.Builder {
+ ctor public Speed.Builder();
+ method public androidx.car.app.hardware.info.Speed build();
+ method public androidx.car.app.hardware.info.Speed.Builder setDisplaySpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public androidx.car.app.hardware.info.Speed.Builder setRawSpeedMetersPerSecond(androidx.car.app.hardware.common.CarValue<java.lang.Float!>);
+ method public androidx.car.app.hardware.info.Speed.Builder setSpeedDisplayUnit(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(3) public final class TollCard {
+ method public androidx.car.app.hardware.common.CarValue<java.lang.Integer!> getCardState();
+ field public static final int TOLLCARD_STATE_INVALID = 2; // 0x2
+ field public static final int TOLLCARD_STATE_NOT_INSERTED = 3; // 0x3
+ field public static final int TOLLCARD_STATE_UNKNOWN = 0; // 0x0
+ field public static final int TOLLCARD_STATE_VALID = 1; // 0x1
+ }
+
+ public static final class TollCard.Builder {
+ ctor public TollCard.Builder();
+ method public androidx.car.app.hardware.info.TollCard build();
+ method public androidx.car.app.hardware.info.TollCard.Builder setCardState(androidx.car.app.hardware.common.CarValue<java.lang.Integer!>);
+ }
+
+}
+
+package androidx.car.app.managers {
+
+ public interface Manager {
+ }
+
+}
+
+package androidx.car.app.media {
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public interface CarAudioCallback {
+ method public void onStopRecording();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public class CarAudioCallbackDelegate {
+ method public void onStopRecording();
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public abstract class CarAudioRecord {
+ method @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public static androidx.car.app.media.CarAudioRecord create(androidx.car.app.CarContext);
+ method public int read(byte[], int, int);
+ method public void startRecording();
+ method public void stopRecording();
+ field public static final int AUDIO_CONTENT_BUFFER_SIZE = 512; // 0x200
+ field public static final String AUDIO_CONTENT_MIME = "audio/l16";
+ field public static final int AUDIO_CONTENT_SAMPLING_RATE = 16000; // 0x3e80
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneRequest {
+ method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallbackDelegate();
+ }
+
+ public static final class OpenMicrophoneRequest.Builder {
+ ctor public OpenMicrophoneRequest.Builder(androidx.car.app.media.CarAudioCallback);
+ method public androidx.car.app.media.OpenMicrophoneRequest build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class OpenMicrophoneResponse {
+ method public androidx.car.app.media.CarAudioCallbackDelegate getCarAudioCallback();
+ method public java.io.InputStream getCarMicrophoneInputStream();
+ }
+
+ public static final class OpenMicrophoneResponse.Builder {
+ ctor public OpenMicrophoneResponse.Builder(androidx.car.app.media.CarAudioCallback);
+ method public androidx.car.app.media.OpenMicrophoneResponse build();
+ method public androidx.car.app.media.OpenMicrophoneResponse.Builder setCarMicrophoneDescriptor(android.os.ParcelFileDescriptor);
+ }
+
+}
+
+package androidx.car.app.mediaextensions {
+
+ public final class MetadataExtras {
+ field public static final String KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_LARGE_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_DARK_MODE_SMALL_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_LARGE_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_LIGHT_MODE_SMALL_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI";
+ field public static final String KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI = "androidx.car.app.mediaextensions.KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI";
+ field public static final String KEY_DESCRIPTION_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_DESCRIPTION_LINK_MEDIA_ID";
+ field public static final String KEY_IMMERSIVE_AUDIO = "androidx.car.app.mediaextensions.KEY_IMMERSIVE_AUDIO";
+ field public static final String KEY_SUBTITLE_LINK_MEDIA_ID = "androidx.car.app.mediaextensions.KEY_SUBTITLE_LINK_MEDIA_ID";
+ }
+
+}
+
+package androidx.car.app.messaging {
+
+ @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public class MessagingServiceConstants {
+ field public static final String ACTION_HANDLE_CAR_MESSAGING = "androidx.car.app.messaging.action.HANDLE_CAR_MESSAGING";
+ }
+
+}
+
+package androidx.car.app.messaging.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class CarMessage {
+ method public androidx.car.app.model.CarText? getBody();
+ method public String? getMultimediaMimeType();
+ method public android.net.Uri? getMultimediaUri();
+ method public long getReceivedTimeEpochMillis();
+ method public androidx.core.app.Person? getSender();
+ method public boolean isRead();
+ }
+
+ public static final class CarMessage.Builder {
+ ctor public CarMessage.Builder();
+ method public androidx.car.app.messaging.model.CarMessage build();
+ method public androidx.car.app.messaging.model.CarMessage.Builder setBody(androidx.car.app.model.CarText?);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaMimeType(String?);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setMultimediaUri(android.net.Uri?);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setRead(boolean);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setReceivedTimeEpochMillis(long);
+ method public androidx.car.app.messaging.model.CarMessage.Builder setSender(androidx.core.app.Person?);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi public interface ConversationCallback {
+ method public void onMarkAsRead();
+ method public void onTextReply(String);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public interface ConversationCallbackDelegate {
+ method public void sendMarkAsRead(androidx.car.app.OnDoneCallback);
+ method public void sendTextReply(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class ConversationItem implements androidx.car.app.model.Item {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.messaging.model.ConversationCallbackDelegate getConversationCallbackDelegate();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public String getId();
+ method public java.util.List<androidx.car.app.messaging.model.CarMessage!> getMessages();
+ method public androidx.core.app.Person getSelf();
+ method public androidx.car.app.model.CarText getTitle();
+ method public boolean isGroupConversation();
+ }
+
+ public static final class ConversationItem.Builder {
+ ctor public ConversationItem.Builder();
+ ctor public ConversationItem.Builder(androidx.car.app.messaging.model.ConversationItem);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.messaging.model.ConversationItem build();
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setConversationCallback(androidx.car.app.messaging.model.ConversationCallback);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setGroupConversation(boolean);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setId(String);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setMessages(java.util.List<androidx.car.app.messaging.model.CarMessage!>);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setSelf(androidx.core.app.Person);
+ method public androidx.car.app.messaging.model.ConversationItem.Builder setTitle(androidx.car.app.model.CarText);
+ }
+
+}
+
+package androidx.car.app.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Action {
+ method public androidx.car.app.model.CarColor? getBackgroundColor();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public int getFlags();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public int getType();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+ method public boolean isStandard();
+ method public static String typeToString(int);
+ field public static final androidx.car.app.model.Action APP_ICON;
+ field public static final androidx.car.app.model.Action BACK;
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.Action COMPOSE_MESSAGE;
+ field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_DEFAULT = 4; // 0x4
+ field @androidx.car.app.annotations.RequiresCarApi(5) public static final int FLAG_IS_PERSISTENT = 2; // 0x2
+ field @androidx.car.app.annotations.RequiresCarApi(4) public static final int FLAG_PRIMARY = 1; // 0x1
+ field public static final androidx.car.app.model.Action PAN;
+ field public static final int TYPE_APP_ICON = 65538; // 0x10002
+ field public static final int TYPE_BACK = 65539; // 0x10003
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int TYPE_COMPOSE_MESSAGE = 65541; // 0x10005
+ field public static final int TYPE_CUSTOM = 1; // 0x1
+ field public static final int TYPE_PAN = 65540; // 0x10004
+ }
+
+ public static final class Action.Builder {
+ ctor public Action.Builder();
+ ctor @androidx.car.app.annotations.RequiresCarApi(2) public Action.Builder(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Action build();
+ method public androidx.car.app.model.Action.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Action.Builder setEnabled(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Action.Builder setFlags(int);
+ method public androidx.car.app.model.Action.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Action.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.Action.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Action.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ActionStrip {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getFirstActionOfType(int);
+ }
+
+ public static final class ActionStrip.Builder {
+ ctor public ActionStrip.Builder();
+ method public androidx.car.app.model.ActionStrip.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.ActionStrip build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Alert {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.AlertCallbackDelegate? getCallbackDelegate();
+ method public long getDurationMillis();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public int getId();
+ method public androidx.car.app.model.CarText? getSubtitle();
+ method public androidx.car.app.model.CarText getTitle();
+ }
+
+ public static final class Alert.Builder {
+ ctor public Alert.Builder(int, androidx.car.app.model.CarText, long);
+ method public androidx.car.app.model.Alert.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Alert build();
+ method public androidx.car.app.model.Alert.Builder setCallback(androidx.car.app.model.AlertCallback);
+ method public androidx.car.app.model.Alert.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Alert.Builder setSubtitle(androidx.car.app.model.CarText);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallback {
+ method public void onCancel(int);
+ method public void onDismiss();
+ field public static final int REASON_NOT_SUPPORTED = 3; // 0x3
+ field public static final int REASON_TIMEOUT = 1; // 0x1
+ field public static final int REASON_USER_ACTION = 2; // 0x2
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface AlertCallbackDelegate {
+ method public void sendCancel(int, androidx.car.app.OnDoneCallback);
+ method public void sendDismiss(androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class Badge {
+ method public androidx.car.app.model.CarColor? getBackgroundColor();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public boolean hasDot();
+ }
+
+ public static final class Badge.Builder {
+ ctor public Badge.Builder();
+ method public androidx.car.app.model.Badge build();
+ method public androidx.car.app.model.Badge.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.model.Badge.Builder setHasDot(boolean);
+ method public androidx.car.app.model.Badge.Builder setIcon(androidx.car.app.model.CarIcon);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarColor {
+ method public static androidx.car.app.model.CarColor createCustom(@ColorInt int, @ColorInt int);
+ method @ColorInt public int getColor();
+ method @ColorInt public int getColorDark();
+ method public int getType();
+ field public static final androidx.car.app.model.CarColor BLUE;
+ field public static final androidx.car.app.model.CarColor DEFAULT;
+ field public static final androidx.car.app.model.CarColor GREEN;
+ field public static final androidx.car.app.model.CarColor PRIMARY;
+ field public static final androidx.car.app.model.CarColor RED;
+ field public static final androidx.car.app.model.CarColor SECONDARY;
+ field public static final int TYPE_BLUE = 6; // 0x6
+ field public static final int TYPE_CUSTOM = 0; // 0x0
+ field public static final int TYPE_DEFAULT = 1; // 0x1
+ field public static final int TYPE_GREEN = 5; // 0x5
+ field public static final int TYPE_PRIMARY = 2; // 0x2
+ field public static final int TYPE_RED = 4; // 0x4
+ field public static final int TYPE_SECONDARY = 3; // 0x3
+ field public static final int TYPE_YELLOW = 7; // 0x7
+ field public static final androidx.car.app.model.CarColor YELLOW;
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIcon {
+ method public androidx.core.graphics.drawable.IconCompat? getIcon();
+ method public androidx.car.app.model.CarColor? getTint();
+ method public int getType();
+ field public static final androidx.car.app.model.CarIcon ALERT;
+ field public static final androidx.car.app.model.CarIcon APP_ICON;
+ field public static final androidx.car.app.model.CarIcon BACK;
+ field @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.CarIcon COMPOSE_MESSAGE;
+ field public static final androidx.car.app.model.CarIcon ERROR;
+ field @androidx.car.app.annotations.RequiresCarApi(2) public static final androidx.car.app.model.CarIcon PAN;
+ field public static final int TYPE_ALERT = 4; // 0x4
+ field public static final int TYPE_APP_ICON = 5; // 0x5
+ field public static final int TYPE_BACK = 3; // 0x3
+ field public static final int TYPE_COMPOSE_MESSAGE = 8; // 0x8
+ field public static final int TYPE_CUSTOM = 1; // 0x1
+ field public static final int TYPE_ERROR = 6; // 0x6
+ field public static final int TYPE_PAN = 7; // 0x7
+ }
+
+ public static final class CarIcon.Builder {
+ ctor public CarIcon.Builder(androidx.car.app.model.CarIcon);
+ ctor public CarIcon.Builder(androidx.core.graphics.drawable.IconCompat);
+ method public androidx.car.app.model.CarIcon build();
+ method public androidx.car.app.model.CarIcon.Builder setTint(androidx.car.app.model.CarColor);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarIconSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon);
+ method public static androidx.car.app.model.CarIconSpan create(androidx.car.app.model.CarIcon, int);
+ method public int getAlignment();
+ method public androidx.car.app.model.CarIcon getIcon();
+ field public static final int ALIGN_BASELINE = 1; // 0x1
+ field public static final int ALIGN_BOTTOM = 0; // 0x0
+ field public static final int ALIGN_CENTER = 2; // 0x2
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarLocation {
+ method public static androidx.car.app.model.CarLocation create(android.location.Location);
+ method public static androidx.car.app.model.CarLocation create(double, double);
+ method public double getLatitude();
+ method public double getLongitude();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public class CarSpan extends android.text.style.CharacterStyle {
+ ctor public CarSpan();
+ method public void updateDrawState(android.text.TextPaint);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class CarText {
+ method public static androidx.car.app.model.CarText create(CharSequence);
+ method public java.util.List<java.lang.CharSequence!> getVariants();
+ method public boolean isEmpty();
+ method public static boolean isNullOrEmpty(androidx.car.app.model.CarText?);
+ method public CharSequence toCharSequence();
+ }
+
+ @SuppressCompatibility public static final class CarText.Builder {
+ ctor public CarText.Builder(CharSequence);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.CarText.Builder addVariant(CharSequence);
+ method public androidx.car.app.model.CarText build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public final class ClickableSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.ClickableSpan create(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.OnClickDelegate getOnClickDelegate();
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface Content {
+ method public String getContentId();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DateTimeWithZone {
+ method @RequiresApi(26) public static androidx.car.app.model.DateTimeWithZone create(java.time.ZonedDateTime);
+ method public static androidx.car.app.model.DateTimeWithZone create(long, @IntRange(from=0xffff02e0, to=64800) int, String);
+ method public static androidx.car.app.model.DateTimeWithZone create(long, java.util.TimeZone);
+ method public long getTimeSinceEpochMillis();
+ method public int getZoneOffsetSeconds();
+ method public String? getZoneShortName();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Distance {
+ method public static androidx.car.app.model.Distance create(double, int);
+ method public double getDisplayDistance();
+ method public int getDisplayUnit();
+ field public static final int UNIT_FEET = 6; // 0x6
+ field public static final int UNIT_KILOMETERS = 2; // 0x2
+ field public static final int UNIT_KILOMETERS_P1 = 3; // 0x3
+ field public static final int UNIT_METERS = 1; // 0x1
+ field public static final int UNIT_MILES = 4; // 0x4
+ field public static final int UNIT_MILES_P1 = 5; // 0x5
+ field public static final int UNIT_YARDS = 7; // 0x7
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DistanceSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.DistanceSpan create(androidx.car.app.model.Distance);
+ method public androidx.car.app.model.Distance getDistance();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class DurationSpan extends androidx.car.app.model.CarSpan {
+ method @RequiresApi(26) public static androidx.car.app.model.DurationSpan create(java.time.Duration);
+ method public static androidx.car.app.model.DurationSpan create(long);
+ method public long getDurationSeconds();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ForegroundCarColorSpan extends androidx.car.app.model.CarSpan {
+ method public static androidx.car.app.model.ForegroundCarColorSpan create(androidx.car.app.model.CarColor);
+ method public androidx.car.app.model.CarColor getColor();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridItem implements androidx.car.app.model.Item {
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.Badge? getBadge();
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public int getImageType();
+ method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+ method public androidx.car.app.model.CarText? getText();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ field public static final int IMAGE_TYPE_ICON = 1; // 0x1
+ field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+ }
+
+ public static final class GridItem.Builder {
+ ctor public GridItem.Builder();
+ method public androidx.car.app.model.GridItem build();
+ method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, androidx.car.app.model.Badge);
+ method public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridItem.Builder setImage(androidx.car.app.model.CarIcon, int, androidx.car.app.model.Badge);
+ method public androidx.car.app.model.GridItem.Builder setLoading(boolean);
+ method public androidx.car.app.model.GridItem.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.GridItem.Builder setText(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.GridItem.Builder setText(CharSequence);
+ method public androidx.car.app.model.GridItem.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.GridItem.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class GridTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemImageShape();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public int getItemSize();
+ method public androidx.car.app.model.ItemList? getSingleList();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_CIRCLE = 2; // 0x2
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_IMAGE_SHAPE_UNSET = 1; // 0x1
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_LARGE = 4; // 0x4
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_MEDIUM = 2; // 0x2
+ field @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public static final int ITEM_SIZE_SMALL = 1; // 0x1
+ }
+
+ public static final class GridTemplate.Builder {
+ ctor public GridTemplate.Builder();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.GridTemplate build();
+ method public androidx.car.app.model.GridTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.GridTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemImageShape(@SuppressCompatibility int);
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public androidx.car.app.model.GridTemplate.Builder setItemSize(@SuppressCompatibility int);
+ method public androidx.car.app.model.GridTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.GridTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.GridTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class Header {
+ method public java.util.List<androidx.car.app.model.Action!> getEndHeaderActions();
+ method public androidx.car.app.model.Action? getStartHeaderAction();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ public static final class Header.Builder {
+ ctor public Header.Builder();
+ method public androidx.car.app.model.Header.Builder addEndHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Header build();
+ method public androidx.car.app.model.Header.Builder setStartHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Header.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Header.Builder setTitle(CharSequence);
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallback {
+ method public default void onInputSubmitted(String);
+ method public default void onInputTextChanged(String);
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public interface InputCallbackDelegate {
+ method public void sendInputSubmitted(String, androidx.car.app.OnDoneCallback);
+ method public void sendInputTextChanged(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface Item {
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ItemList {
+ method public java.util.List<androidx.car.app.model.Item!> getItems();
+ method public androidx.car.app.model.CarText? getNoItemsMessage();
+ method public androidx.car.app.model.OnItemVisibilityChangedDelegate? getOnItemVisibilityChangedDelegate();
+ method public androidx.car.app.model.OnSelectedDelegate? getOnSelectedDelegate();
+ method public int getSelectedIndex();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder toBuilder();
+ }
+
+ public static final class ItemList.Builder {
+ ctor public ItemList.Builder();
+ method public androidx.car.app.model.ItemList.Builder addItem(androidx.car.app.model.Item);
+ method public androidx.car.app.model.ItemList build();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ItemList.Builder clearItems();
+ method public androidx.car.app.model.ItemList.Builder setNoItemsMessage(CharSequence);
+ method public androidx.car.app.model.ItemList.Builder setOnItemsVisibilityChangedListener(androidx.car.app.model.ItemList.OnItemVisibilityChangedListener);
+ method public androidx.car.app.model.ItemList.Builder setOnSelectedListener(androidx.car.app.model.ItemList.OnSelectedListener);
+ method public androidx.car.app.model.ItemList.Builder setSelectedIndex(@IntRange(from=0) int);
+ }
+
+ public static interface ItemList.OnItemVisibilityChangedListener {
+ method public void onItemVisibilityChanged(int, int);
+ }
+
+ public static interface ItemList.OnSelectedListener {
+ method public void onSelected(int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ListTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public java.util.List<androidx.car.app.model.SectionedItemList!> getSectionedLists();
+ method public androidx.car.app.model.ItemList? getSingleList();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder toBuilder();
+ }
+
+ public static final class ListTemplate.Builder {
+ ctor public ListTemplate.Builder();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.ListTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.ListTemplate.Builder addSectionedList(androidx.car.app.model.SectionedItemList);
+ method public androidx.car.app.model.ListTemplate build();
+ method @SuppressCompatibility @androidx.car.app.annotations.ExperimentalCarApi public androidx.car.app.model.ListTemplate.Builder clearSectionedLists();
+ method public androidx.car.app.model.ListTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.ListTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.ListTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.ListTemplate.Builder setSingleList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.ListTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class LongMessageTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.CarText getMessage();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public static final class LongMessageTemplate.Builder {
+ ctor public LongMessageTemplate.Builder(CharSequence);
+ method public androidx.car.app.model.LongMessageTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.LongMessageTemplate build();
+ method public androidx.car.app.model.LongMessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.LongMessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.LongMessageTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageTemplate implements androidx.car.app.model.Template {
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.CarText? getDebugMessage();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public androidx.car.app.model.CarText getMessage();
+ method public androidx.car.app.model.CarText? getTitle();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public boolean isLoading();
+ }
+
+ public static final class MessageTemplate.Builder {
+ ctor public MessageTemplate.Builder(androidx.car.app.model.CarText);
+ ctor public MessageTemplate.Builder(CharSequence);
+ method public androidx.car.app.model.MessageTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.MessageTemplate build();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(String);
+ method public androidx.car.app.model.MessageTemplate.Builder setDebugMessage(Throwable);
+ method public androidx.car.app.model.MessageTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.MessageTemplate.Builder setIcon(androidx.car.app.model.CarIcon);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.MessageTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.MessageTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Metadata {
+ method public androidx.car.app.model.Place? getPlace();
+ field public static final androidx.car.app.model.Metadata EMPTY_METADATA;
+ }
+
+ public static final class Metadata.Builder {
+ ctor public Metadata.Builder();
+ ctor public Metadata.Builder(androidx.car.app.model.Metadata);
+ method public androidx.car.app.model.Metadata build();
+ method public androidx.car.app.model.Metadata.Builder setPlace(androidx.car.app.model.Place);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnCheckedChangeDelegate {
+ method public void sendCheckedChange(boolean, androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnClickDelegate {
+ method public boolean isParkedOnly();
+ method public void sendClick(androidx.car.app.OnDoneCallback);
+ }
+
+ public interface OnClickListener {
+ method public void onClick();
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshDelegate {
+ method public void sendContentRefreshRequested(androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public interface OnContentRefreshListener {
+ method public void onContentRefreshRequested();
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnItemVisibilityChangedDelegate {
+ method public void sendItemVisibilityChanged(int, int, androidx.car.app.OnDoneCallback);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface OnSelectedDelegate {
+ method public void sendSelected(int, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Pane {
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.CarIcon? getImage();
+ method public java.util.List<androidx.car.app.model.Row!> getRows();
+ method public boolean isLoading();
+ }
+
+ public static final class Pane.Builder {
+ ctor public Pane.Builder();
+ method public androidx.car.app.model.Pane.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Pane.Builder addRow(androidx.car.app.model.Row);
+ method public androidx.car.app.model.Pane build();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.Pane.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Pane.Builder setLoading(boolean);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PaneTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.Pane getPane();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ public static final class PaneTemplate.Builder {
+ ctor public PaneTemplate.Builder(androidx.car.app.model.Pane);
+ method public androidx.car.app.model.PaneTemplate build();
+ method public androidx.car.app.model.PaneTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.PaneTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.PaneTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class ParkedOnlyOnClickListener implements androidx.car.app.model.OnClickListener {
+ method public static androidx.car.app.model.ParkedOnlyOnClickListener create(androidx.car.app.model.OnClickListener);
+ method public void onClick();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Place {
+ method public androidx.car.app.model.CarLocation getLocation();
+ method public androidx.car.app.model.PlaceMarker? getMarker();
+ }
+
+ public static final class Place.Builder {
+ ctor public Place.Builder(androidx.car.app.model.CarLocation);
+ ctor public Place.Builder(androidx.car.app.model.Place);
+ method public androidx.car.app.model.Place build();
+ method public androidx.car.app.model.Place.Builder setMarker(androidx.car.app.model.PlaceMarker);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListMapTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Place? getAnchor();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isCurrentLocationEnabled();
+ method public boolean isLoading();
+ }
+
+ public static final class PlaceListMapTemplate.Builder {
+ ctor public PlaceListMapTemplate.Builder();
+ method public androidx.car.app.model.PlaceListMapTemplate build();
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setAnchor(androidx.car.app.model.Place);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setCurrentLocationEnabled(boolean);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setLoading(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.PlaceListMapTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.PlaceListMapTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceMarker {
+ method public androidx.car.app.model.CarColor? getColor();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public int getIconType();
+ method public androidx.car.app.model.CarText? getLabel();
+ field public static final int TYPE_ICON = 0; // 0x0
+ field public static final int TYPE_IMAGE = 1; // 0x1
+ }
+
+ public static final class PlaceMarker.Builder {
+ ctor public PlaceMarker.Builder();
+ method public androidx.car.app.model.PlaceMarker build();
+ method public androidx.car.app.model.PlaceMarker.Builder setColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.model.PlaceMarker.Builder setIcon(androidx.car.app.model.CarIcon, int);
+ method public androidx.car.app.model.PlaceMarker.Builder setLabel(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Row implements androidx.car.app.model.Item {
+ method @androidx.car.app.annotations.RequiresCarApi(6) public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public androidx.car.app.model.Metadata? getMetadata();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public int getNumericDecoration();
+ method public androidx.car.app.model.OnClickDelegate? getOnClickDelegate();
+ method public int getRowImageType();
+ method public java.util.List<androidx.car.app.model.CarText!> getTexts();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public androidx.car.app.model.Toggle? getToggle();
+ method public boolean isBrowsable();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+ method public androidx.car.app.model.Row row();
+ method public CharSequence yourBoat();
+ field public static final int IMAGE_TYPE_ICON = 4; // 0x4
+ field public static final int IMAGE_TYPE_LARGE = 2; // 0x2
+ field public static final int IMAGE_TYPE_SMALL = 1; // 0x1
+ field public static final int NO_DECORATION = -1; // 0xffffffff
+ }
+
+ public static final class Row.Builder {
+ ctor public Row.Builder();
+ method @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Row.Builder addText(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Row.Builder addText(CharSequence);
+ method public androidx.car.app.model.Row build();
+ method public androidx.car.app.model.Row.Builder setBrowsable(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Row.Builder setEnabled(boolean);
+ method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Row.Builder setImage(androidx.car.app.model.CarIcon, int);
+ method public androidx.car.app.model.Row.Builder setMetadata(androidx.car.app.model.Metadata);
+ method @IntRange(from=0) @androidx.car.app.annotations.RequiresCarApi(6) public androidx.car.app.model.Row.Builder setNumericDecoration(int);
+ method public androidx.car.app.model.Row.Builder setOnClickListener(androidx.car.app.model.OnClickListener);
+ method public androidx.car.app.model.Row.Builder setTitle(androidx.car.app.model.CarText);
+ method public androidx.car.app.model.Row.Builder setTitle(CharSequence);
+ method public androidx.car.app.model.Row.Builder setToggle(androidx.car.app.model.Toggle);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface SearchCallbackDelegate {
+ method public void sendSearchSubmitted(String, androidx.car.app.OnDoneCallback);
+ method public void sendSearchTextChanged(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SearchTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public String? getInitialSearchText();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method public androidx.car.app.model.SearchCallbackDelegate getSearchCallbackDelegate();
+ method public String? getSearchHint();
+ method public boolean isLoading();
+ method public boolean isShowKeyboardByDefault();
+ }
+
+ public static final class SearchTemplate.Builder {
+ ctor public SearchTemplate.Builder(androidx.car.app.model.SearchTemplate.SearchCallback);
+ method public androidx.car.app.model.SearchTemplate build();
+ method public androidx.car.app.model.SearchTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.SearchTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.SearchTemplate.Builder setInitialSearchText(String);
+ method public androidx.car.app.model.SearchTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.model.SearchTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.SearchTemplate.Builder setSearchHint(String);
+ method public androidx.car.app.model.SearchTemplate.Builder setShowKeyboardByDefault(boolean);
+ }
+
+ public static interface SearchTemplate.SearchCallback {
+ method public default void onSearchSubmitted(String);
+ method public default void onSearchTextChanged(String);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class SectionedItemList {
+ method public static androidx.car.app.model.SectionedItemList create(androidx.car.app.model.ItemList, CharSequence);
+ method public androidx.car.app.model.CarText getHeader();
+ method public androidx.car.app.model.ItemList getItemList();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public final class Tab implements androidx.car.app.model.Content {
+ method public String getContentId();
+ method public androidx.car.app.model.CarIcon getIcon();
+ method public androidx.car.app.model.CarText getTitle();
+ }
+
+ public static final class Tab.Builder {
+ ctor public Tab.Builder();
+ ctor public Tab.Builder(androidx.car.app.model.Tab);
+ method public androidx.car.app.model.Tab build();
+ method public androidx.car.app.model.Tab.Builder setContentId(String);
+ method public androidx.car.app.model.Tab.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.model.Tab.Builder setTitle(CharSequence);
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public interface TabCallbackDelegate {
+ method public void sendTabSelected(String, androidx.car.app.OnDoneCallback);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabContents implements androidx.car.app.model.Content {
+ method public String getContentId();
+ method public androidx.car.app.model.Template getTemplate();
+ field public static final String CONTENT_ID = "TAB_CONTENTS_CONTENT_ID";
+ }
+
+ public static final class TabContents.Builder {
+ ctor public TabContents.Builder(androidx.car.app.model.Template);
+ method public androidx.car.app.model.TabContents build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(6) public class TabTemplate implements androidx.car.app.model.Template {
+ method public String getActiveTabContentId();
+ method public androidx.car.app.model.Action getHeaderAction();
+ method public androidx.car.app.model.TabCallbackDelegate getTabCallbackDelegate();
+ method public androidx.car.app.model.TabContents getTabContents();
+ method public java.util.List<androidx.car.app.model.Tab!> getTabs();
+ method public boolean isLoading();
+ }
+
+ public static final class TabTemplate.Builder {
+ ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate);
+ ctor public TabTemplate.Builder(androidx.car.app.model.TabTemplate.TabCallback);
+ method public androidx.car.app.model.TabTemplate.Builder addTab(androidx.car.app.model.Tab);
+ method public androidx.car.app.model.TabTemplate build();
+ method public androidx.car.app.model.TabTemplate.Builder setActiveTabContentId(String);
+ method public androidx.car.app.model.TabTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.TabTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.TabTemplate.Builder setTabContents(androidx.car.app.model.TabContents);
+ }
+
+ public static interface TabTemplate.TabCallback {
+ method public default void onTabSelected(String);
+ }
+
+ @androidx.car.app.annotations.CarProtocol public interface Template {
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateInfo {
+ ctor public TemplateInfo(Class<? extends androidx.car.app.model.Template>, String);
+ method public Class<? extends androidx.car.app.model.Template> getTemplateClass();
+ method public String getTemplateId();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TemplateWrapper {
+ method public static androidx.car.app.model.TemplateWrapper copyOf(androidx.car.app.model.TemplateWrapper);
+ method public int getCurrentTaskStep();
+ method public String getId();
+ method public androidx.car.app.model.Template getTemplate();
+ method public java.util.List<androidx.car.app.model.TemplateInfo!> getTemplateInfosForScreenStack();
+ method public boolean isRefresh();
+ method public void setCurrentTaskStep(int);
+ method public void setId(String);
+ method public void setRefresh(boolean);
+ method public void setTemplate(androidx.car.app.model.Template);
+ method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template);
+ method public static androidx.car.app.model.TemplateWrapper wrap(androidx.car.app.model.Template, String);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Toggle {
+ method public androidx.car.app.model.OnCheckedChangeDelegate getOnCheckedChangeDelegate();
+ method public boolean isChecked();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public boolean isEnabled();
+ }
+
+ public static final class Toggle.Builder {
+ ctor public Toggle.Builder(androidx.car.app.model.Toggle.OnCheckedChangeListener);
+ method public androidx.car.app.model.Toggle build();
+ method public androidx.car.app.model.Toggle.Builder setChecked(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Toggle.Builder setEnabled(boolean);
+ }
+
+ public static interface Toggle.OnCheckedChangeListener {
+ method public void onCheckedChange(boolean);
+ }
+
+}
+
+package androidx.car.app.model.signin {
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class InputSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ 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 public androidx.car.app.model.InputCallbackDelegate getInputCallbackDelegate();
+ method public int getInputType();
+ method public int getKeyboardType();
+ method public boolean isShowKeyboardByDefault();
+ field public static final int INPUT_TYPE_DEFAULT = 1; // 0x1
+ field public static final int INPUT_TYPE_PASSWORD = 2; // 0x2
+ field public static final int KEYBOARD_DEFAULT = 1; // 0x1
+ field public static final int KEYBOARD_EMAIL = 2; // 0x2
+ field public static final int KEYBOARD_NUMBER = 4; // 0x4
+ field public static final int KEYBOARD_PHONE = 3; // 0x3
+ }
+
+ public static final class InputSignInMethod.Builder {
+ 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);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setHint(CharSequence);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setInputType(int);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setKeyboardType(int);
+ method public androidx.car.app.model.signin.InputSignInMethod.Builder setShowKeyboardByDefault(boolean);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class PinSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ ctor public PinSignInMethod(CharSequence);
+ method public androidx.car.app.model.CarText getPinCode();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class ProviderSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ ctor public ProviderSignInMethod(androidx.car.app.model.Action);
+ method public androidx.car.app.model.Action getAction();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(4) public final class QRCodeSignInMethod implements androidx.car.app.model.signin.SignInTemplate.SignInMethod {
+ ctor public QRCodeSignInMethod(android.net.Uri);
+ method public android.net.Uri getUri();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.RequiresCarApi(2) public final class SignInTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public java.util.List<androidx.car.app.model.Action!> getActions();
+ method public androidx.car.app.model.CarText? getAdditionalText();
+ method public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.CarText? getInstructions();
+ method public androidx.car.app.model.signin.SignInTemplate.SignInMethod getSignInMethod();
+ method public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ }
+
+ @androidx.car.app.annotations.RequiresCarApi(2) public static final class SignInTemplate.Builder {
+ ctor public SignInTemplate.Builder(androidx.car.app.model.signin.SignInTemplate.SignInMethod);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder addAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.signin.SignInTemplate build();
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setAdditionalText(CharSequence);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setInstructions(CharSequence);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.model.signin.SignInTemplate.Builder setTitle(CharSequence);
+ }
+
+ public static interface SignInTemplate.SignInMethod {
+ }
+
+}
+
+package androidx.car.app.navigation {
+
+ public class NavigationManager implements androidx.car.app.managers.Manager {
+ method @MainThread public void clearNavigationManagerCallback();
+ method @MainThread public void navigationEnded();
+ method @MainThread public void navigationStarted();
+ method @MainThread public void setNavigationManagerCallback(androidx.car.app.navigation.NavigationManagerCallback);
+ method @MainThread public void setNavigationManagerCallback(java.util.concurrent.Executor, androidx.car.app.navigation.NavigationManagerCallback);
+ method @MainThread public void updateTrip(androidx.car.app.navigation.model.Trip);
+ }
+
+ public interface NavigationManagerCallback {
+ method public default void onAutoDriveEnabled();
+ method public default void onStopNavigation();
+ }
+
+}
+
+package androidx.car.app.navigation.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Destination {
+ method public androidx.car.app.model.CarText? getAddress();
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public androidx.car.app.model.CarText? getName();
+ }
+
+ public static final class Destination.Builder {
+ ctor public Destination.Builder();
+ method public androidx.car.app.navigation.model.Destination build();
+ method public androidx.car.app.navigation.model.Destination.Builder setAddress(CharSequence);
+ method public androidx.car.app.navigation.model.Destination.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.Destination.Builder setName(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Lane {
+ method public java.util.List<androidx.car.app.navigation.model.LaneDirection!> getDirections();
+ }
+
+ public static final class Lane.Builder {
+ ctor public Lane.Builder();
+ method public androidx.car.app.navigation.model.Lane.Builder addDirection(androidx.car.app.navigation.model.LaneDirection);
+ method public androidx.car.app.navigation.model.Lane build();
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class LaneDirection {
+ method public static androidx.car.app.navigation.model.LaneDirection create(int, boolean);
+ method public int getShape();
+ method public boolean isRecommended();
+ field public static final int SHAPE_NORMAL_LEFT = 5; // 0x5
+ field public static final int SHAPE_NORMAL_RIGHT = 6; // 0x6
+ field public static final int SHAPE_SHARP_LEFT = 7; // 0x7
+ field public static final int SHAPE_SHARP_RIGHT = 8; // 0x8
+ field public static final int SHAPE_SLIGHT_LEFT = 3; // 0x3
+ field public static final int SHAPE_SLIGHT_RIGHT = 4; // 0x4
+ field public static final int SHAPE_STRAIGHT = 2; // 0x2
+ field public static final int SHAPE_UNKNOWN = 1; // 0x1
+ field public static final int SHAPE_U_TURN_LEFT = 9; // 0x9
+ field public static final int SHAPE_U_TURN_RIGHT = 10; // 0xa
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Maneuver {
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public int getRoundaboutExitAngle();
+ method public int getRoundaboutExitNumber();
+ method public int getType();
+ field public static final int TYPE_DEPART = 1; // 0x1
+ field public static final int TYPE_DESTINATION = 39; // 0x27
+ field public static final int TYPE_DESTINATION_LEFT = 41; // 0x29
+ field public static final int TYPE_DESTINATION_RIGHT = 42; // 0x2a
+ field public static final int TYPE_DESTINATION_STRAIGHT = 40; // 0x28
+ field public static final int TYPE_FERRY_BOAT = 37; // 0x25
+ field public static final int TYPE_FERRY_BOAT_LEFT = 47; // 0x2f
+ field public static final int TYPE_FERRY_BOAT_RIGHT = 48; // 0x30
+ field public static final int TYPE_FERRY_TRAIN = 38; // 0x26
+ field public static final int TYPE_FERRY_TRAIN_LEFT = 49; // 0x31
+ field public static final int TYPE_FERRY_TRAIN_RIGHT = 50; // 0x32
+ field public static final int TYPE_FORK_LEFT = 25; // 0x19
+ field public static final int TYPE_FORK_RIGHT = 26; // 0x1a
+ field public static final int TYPE_KEEP_LEFT = 3; // 0x3
+ field public static final int TYPE_KEEP_RIGHT = 4; // 0x4
+ field public static final int TYPE_MERGE_LEFT = 27; // 0x1b
+ field public static final int TYPE_MERGE_RIGHT = 28; // 0x1c
+ field public static final int TYPE_MERGE_SIDE_UNSPECIFIED = 29; // 0x1d
+ field public static final int TYPE_NAME_CHANGE = 2; // 0x2
+ field public static final int TYPE_OFF_RAMP_NORMAL_LEFT = 23; // 0x17
+ field public static final int TYPE_OFF_RAMP_NORMAL_RIGHT = 24; // 0x18
+ field public static final int TYPE_OFF_RAMP_SLIGHT_LEFT = 21; // 0x15
+ field public static final int TYPE_OFF_RAMP_SLIGHT_RIGHT = 22; // 0x16
+ field public static final int TYPE_ON_RAMP_NORMAL_LEFT = 15; // 0xf
+ field public static final int TYPE_ON_RAMP_NORMAL_RIGHT = 16; // 0x10
+ field public static final int TYPE_ON_RAMP_SHARP_LEFT = 17; // 0x11
+ field public static final int TYPE_ON_RAMP_SHARP_RIGHT = 18; // 0x12
+ field public static final int TYPE_ON_RAMP_SLIGHT_LEFT = 13; // 0xd
+ field public static final int TYPE_ON_RAMP_SLIGHT_RIGHT = 14; // 0xe
+ field public static final int TYPE_ON_RAMP_U_TURN_LEFT = 19; // 0x13
+ field public static final int TYPE_ON_RAMP_U_TURN_RIGHT = 20; // 0x14
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW = 34; // 0x22
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CCW_WITH_ANGLE = 35; // 0x23
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW = 32; // 0x20
+ field public static final int TYPE_ROUNDABOUT_ENTER_AND_EXIT_CW_WITH_ANGLE = 33; // 0x21
+ field public static final int TYPE_ROUNDABOUT_ENTER_CCW = 45; // 0x2d
+ field public static final int TYPE_ROUNDABOUT_ENTER_CW = 43; // 0x2b
+ field public static final int TYPE_ROUNDABOUT_EXIT_CCW = 46; // 0x2e
+ field public static final int TYPE_ROUNDABOUT_EXIT_CW = 44; // 0x2c
+ field public static final int TYPE_STRAIGHT = 36; // 0x24
+ field public static final int TYPE_TURN_NORMAL_LEFT = 7; // 0x7
+ field public static final int TYPE_TURN_NORMAL_RIGHT = 8; // 0x8
+ field public static final int TYPE_TURN_SHARP_LEFT = 9; // 0x9
+ field public static final int TYPE_TURN_SHARP_RIGHT = 10; // 0xa
+ field public static final int TYPE_TURN_SLIGHT_LEFT = 5; // 0x5
+ field public static final int TYPE_TURN_SLIGHT_RIGHT = 6; // 0x6
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
+ field public static final int TYPE_U_TURN_LEFT = 11; // 0xb
+ field public static final int TYPE_U_TURN_RIGHT = 12; // 0xc
+ }
+
+ public static final class Maneuver.Builder {
+ ctor public Maneuver.Builder(int);
+ method public androidx.car.app.navigation.model.Maneuver build();
+ method public androidx.car.app.navigation.model.Maneuver.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitAngle(@IntRange(from=1, to=360) int);
+ method public androidx.car.app.navigation.model.Maneuver.Builder setRoundaboutExitNumber(@IntRange(from=1) int);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapController {
+ method public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ }
+
+ public static final class MapController.Builder {
+ ctor public MapController.Builder();
+ method public androidx.car.app.navigation.model.MapController build();
+ method public androidx.car.app.navigation.model.MapController.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.MapController.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(5) public final class MapTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Header? getHeader();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method public androidx.car.app.navigation.model.MapController? getMapController();
+ method public androidx.car.app.model.Pane? getPane();
+ }
+
+ public static final class MapTemplate.Builder {
+ ctor public MapTemplate.Builder();
+ method public androidx.car.app.navigation.model.MapTemplate build();
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setHeader(androidx.car.app.model.Header);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+ method public androidx.car.app.navigation.model.MapTemplate.Builder setPane(androidx.car.app.model.Pane);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public final class MapWithContentTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.Template? getContentTemplate();
+ method public androidx.car.app.navigation.model.MapController? getMapController();
+ method public boolean isLoading();
+ }
+
+ public static final class MapWithContentTemplate.Builder {
+ ctor public MapWithContentTemplate.Builder();
+ method public androidx.car.app.navigation.model.MapWithContentTemplate build();
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setContentTemplate(androidx.car.app.model.Template);
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setLoading(boolean);
+ method public androidx.car.app.navigation.model.MapWithContentTemplate.Builder setMapController(androidx.car.app.navigation.model.MapController);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class MessageInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+ method public androidx.car.app.model.CarIcon? getImage();
+ method public androidx.car.app.model.CarText? getText();
+ method public androidx.car.app.model.CarText? getTitle();
+ }
+
+ public static final class MessageInfo.Builder {
+ ctor public MessageInfo.Builder(androidx.car.app.model.CarText);
+ ctor public MessageInfo.Builder(CharSequence);
+ method public androidx.car.app.navigation.model.MessageInfo build();
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setText(androidx.car.app.model.CarText);
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setText(CharSequence);
+ method public androidx.car.app.navigation.model.MessageInfo.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class NavigationTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method public androidx.car.app.model.CarColor? getBackgroundColor();
+ method public androidx.car.app.navigation.model.TravelEstimate? getDestinationTravelEstimate();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo? getNavigationInfo();
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ method @Deprecated @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.model.Toggle? getPanModeToggle();
+ }
+
+ public static final class NavigationTemplate.Builder {
+ ctor public NavigationTemplate.Builder();
+ method public androidx.car.app.navigation.model.NavigationTemplate build();
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setBackgroundColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setDestinationTravelEstimate(androidx.car.app.navigation.model.TravelEstimate);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.NavigationTemplate.Builder setNavigationInfo(androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo);
+ method @androidx.car.app.annotations.RequiresCarApi(2) public androidx.car.app.navigation.model.NavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ }
+
+ public static interface NavigationTemplate.NavigationInfo {
+ }
+
+ @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.RequiresCarApi(2) public interface PanModeDelegate {
+ method public void sendPanModeChanged(boolean, androidx.car.app.OnDoneCallback);
+ }
+
+ public interface PanModeListener {
+ method public void onPanModeChanged(boolean);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class PlaceListNavigationTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+ method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.model.OnContentRefreshDelegate? getOnContentRefreshDelegate();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ method @Deprecated public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ }
+
+ public static final class PlaceListNavigationTemplate.Builder {
+ ctor public PlaceListNavigationTemplate.Builder();
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate build();
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+ method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setLoading(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setOnContentRefreshListener(androidx.car.app.model.OnContentRefreshListener);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+ method @Deprecated public androidx.car.app.navigation.model.PlaceListNavigationTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutePreviewNavigationTemplate implements androidx.car.app.model.Template {
+ method public androidx.car.app.model.ActionStrip? getActionStrip();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.Header? getHeader();
+ method @Deprecated public androidx.car.app.model.Action? getHeaderAction();
+ method public androidx.car.app.model.ItemList? getItemList();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.model.ActionStrip? getMapActionStrip();
+ method public androidx.car.app.model.Action? getNavigateAction();
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.PanModeDelegate? getPanModeDelegate();
+ method @Deprecated public androidx.car.app.model.CarText? getTitle();
+ method public boolean isLoading();
+ }
+
+ public static final class RoutePreviewNavigationTemplate.Builder {
+ ctor public RoutePreviewNavigationTemplate.Builder();
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate build();
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setActionStrip(androidx.car.app.model.ActionStrip);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeader(androidx.car.app.model.Header);
+ method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setHeaderAction(androidx.car.app.model.Action);
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setItemList(androidx.car.app.model.ItemList);
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setLoading(boolean);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setMapActionStrip(androidx.car.app.model.ActionStrip);
+ method public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setNavigateAction(androidx.car.app.model.Action);
+ method @androidx.car.app.annotations.RequiresCarApi(4) public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setPanModeListener(androidx.car.app.navigation.model.PanModeListener);
+ method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(androidx.car.app.model.CarText);
+ method @Deprecated public androidx.car.app.navigation.model.RoutePreviewNavigationTemplate.Builder setTitle(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class RoutingInfo implements androidx.car.app.navigation.model.NavigationTemplate.NavigationInfo {
+ method public androidx.car.app.model.Distance? getCurrentDistance();
+ method public androidx.car.app.navigation.model.Step? getCurrentStep();
+ method public androidx.car.app.model.CarIcon? getJunctionImage();
+ method public androidx.car.app.navigation.model.Step? getNextStep();
+ method public boolean isLoading();
+ }
+
+ public static final class RoutingInfo.Builder {
+ ctor public RoutingInfo.Builder();
+ method public androidx.car.app.navigation.model.RoutingInfo build();
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setCurrentStep(androidx.car.app.navigation.model.Step, androidx.car.app.model.Distance);
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setJunctionImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setLoading(boolean);
+ method public androidx.car.app.navigation.model.RoutingInfo.Builder setNextStep(androidx.car.app.navigation.model.Step);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Step {
+ method public androidx.car.app.model.CarText? getCue();
+ method public java.util.List<androidx.car.app.navigation.model.Lane!> getLanes();
+ method public androidx.car.app.model.CarIcon? getLanesImage();
+ method public androidx.car.app.navigation.model.Maneuver? getManeuver();
+ method public androidx.car.app.model.CarText? getRoad();
+ }
+
+ public static final class Step.Builder {
+ ctor public Step.Builder();
+ ctor public Step.Builder(androidx.car.app.model.CarText);
+ ctor public Step.Builder(CharSequence);
+ method public androidx.car.app.navigation.model.Step.Builder addLane(androidx.car.app.navigation.model.Lane);
+ method public androidx.car.app.navigation.model.Step build();
+ method public androidx.car.app.navigation.model.Step.Builder setCue(CharSequence);
+ method public androidx.car.app.navigation.model.Step.Builder setLanesImage(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.navigation.model.Step.Builder setManeuver(androidx.car.app.navigation.model.Maneuver);
+ method public androidx.car.app.navigation.model.Step.Builder setRoad(CharSequence);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class TravelEstimate {
+ method public androidx.car.app.model.DateTimeWithZone? getArrivalTimeAtDestination();
+ method public androidx.car.app.model.Distance? getRemainingDistance();
+ method public androidx.car.app.model.CarColor? getRemainingDistanceColor();
+ method public androidx.car.app.model.CarColor? getRemainingTimeColor();
+ method public long getRemainingTimeSeconds();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarIcon? getTripIcon();
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.model.CarText? getTripText();
+ field public static final long REMAINING_TIME_UNKNOWN = -1L; // 0xffffffffffffffffL
+ }
+
+ public static final class TravelEstimate.Builder {
+ ctor public TravelEstimate.Builder(androidx.car.app.model.Distance, androidx.car.app.model.DateTimeWithZone);
+ ctor @RequiresApi(26) public TravelEstimate.Builder(androidx.car.app.model.Distance, java.time.ZonedDateTime);
+ method public androidx.car.app.navigation.model.TravelEstimate build();
+ method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingDistanceColor(androidx.car.app.model.CarColor);
+ method @RequiresApi(26) public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTime(java.time.Duration);
+ method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.navigation.model.TravelEstimate.Builder setRemainingTimeSeconds(@IntRange(from=0xffffffff) long);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripIcon(androidx.car.app.model.CarIcon);
+ method @androidx.car.app.annotations.RequiresCarApi(5) public androidx.car.app.navigation.model.TravelEstimate.Builder setTripText(androidx.car.app.model.CarText);
+ }
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Trip {
+ method public androidx.car.app.model.CarText? getCurrentRoad();
+ method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getDestinationTravelEstimates();
+ method public java.util.List<androidx.car.app.navigation.model.Destination!> getDestinations();
+ method public java.util.List<androidx.car.app.navigation.model.TravelEstimate!> getStepTravelEstimates();
+ method public java.util.List<androidx.car.app.navigation.model.Step!> getSteps();
+ method public boolean isLoading();
+ }
+
+ public static final class Trip.Builder {
+ ctor public Trip.Builder();
+ method public androidx.car.app.navigation.model.Trip.Builder addDestination(androidx.car.app.navigation.model.Destination, androidx.car.app.navigation.model.TravelEstimate);
+ method public androidx.car.app.navigation.model.Trip.Builder addStep(androidx.car.app.navigation.model.Step, androidx.car.app.navigation.model.TravelEstimate);
+ method public androidx.car.app.navigation.model.Trip build();
+ method public androidx.car.app.navigation.model.Trip.Builder setCurrentRoad(CharSequence);
+ method public androidx.car.app.navigation.model.Trip.Builder setLoading(boolean);
+ }
+
+}
+
+package androidx.car.app.notification {
+
+ public final class CarAppExtender implements androidx.core.app.NotificationCompat.Extender {
+ ctor public CarAppExtender(android.app.Notification);
+ method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+ method public java.util.List<android.app.Notification.Action!> getActions();
+ method public String? getChannelId();
+ method public androidx.car.app.model.CarColor? getColor();
+ method public android.app.PendingIntent? getContentIntent();
+ method public CharSequence? getContentText();
+ method public CharSequence? getContentTitle();
+ method public android.app.PendingIntent? getDeleteIntent();
+ method public int getImportance();
+ method public android.graphics.Bitmap? getLargeIcon();
+ method @DrawableRes public int getSmallIcon();
+ method public static boolean isExtended(android.app.Notification);
+ }
+
+ public static final class CarAppExtender.Builder {
+ ctor public CarAppExtender.Builder();
+ method public androidx.car.app.notification.CarAppExtender.Builder addAction(@DrawableRes int, CharSequence, android.app.PendingIntent);
+ method public androidx.car.app.notification.CarAppExtender build();
+ method public androidx.car.app.notification.CarAppExtender.Builder setChannelId(String);
+ method public androidx.car.app.notification.CarAppExtender.Builder setColor(androidx.car.app.model.CarColor);
+ method public androidx.car.app.notification.CarAppExtender.Builder setContentIntent(android.app.PendingIntent);
+ method public androidx.car.app.notification.CarAppExtender.Builder setContentText(CharSequence);
+ method public androidx.car.app.notification.CarAppExtender.Builder setContentTitle(CharSequence);
+ method public androidx.car.app.notification.CarAppExtender.Builder setDeleteIntent(android.app.PendingIntent);
+ method public androidx.car.app.notification.CarAppExtender.Builder setImportance(int);
+ method public androidx.car.app.notification.CarAppExtender.Builder setLargeIcon(android.graphics.Bitmap);
+ method public androidx.car.app.notification.CarAppExtender.Builder setSmallIcon(int);
+ }
+
+ public final class CarNotificationManager {
+ method public boolean areNotificationsEnabled();
+ method public void cancel(int);
+ method public void cancel(String?, int);
+ method public void cancelAll();
+ method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+ method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+ method public void createNotificationChannelGroups(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+ method public void createNotificationChannels(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+ method public void deleteNotificationChannel(String);
+ method public void deleteNotificationChannelGroup(String);
+ method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+ method public static androidx.car.app.notification.CarNotificationManager from(android.content.Context);
+ method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+ method public int getImportance();
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String);
+ method public androidx.core.app.NotificationChannelCompat? getNotificationChannel(String, String);
+ method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroup(String);
+ method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroups();
+ method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannels();
+ method public void notify(int, androidx.core.app.NotificationCompat.Builder);
+ method public void notify(String?, int, androidx.core.app.NotificationCompat.Builder);
+ }
+
+ public final class CarPendingIntent {
+ method public static android.app.PendingIntent getCarApp(android.content.Context, int, android.content.Intent, int);
+ }
+
+}
+
+package androidx.car.app.serialization {
+
+ public final class Bundleable implements android.os.Parcelable {
+ method public static androidx.car.app.serialization.Bundleable create(Object) throws androidx.car.app.serialization.BundlerException;
+ method public int describeContents();
+ method public Object get() throws androidx.car.app.serialization.BundlerException;
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<androidx.car.app.serialization.Bundleable!> CREATOR;
+ }
+
+ public class BundlerException extends java.lang.Exception {
+ ctor public BundlerException(String?);
+ ctor public BundlerException(String?, Throwable);
+ }
+
+}
+
+package androidx.car.app.suggestion {
+
+ @androidx.car.app.annotations.RequiresCarApi(5) public class SuggestionManager implements androidx.car.app.managers.Manager {
+ method @MainThread public void updateSuggestions(java.util.List<androidx.car.app.suggestion.model.Suggestion!>);
+ }
+
+}
+
+package androidx.car.app.suggestion.model {
+
+ @SuppressCompatibility @androidx.car.app.annotations.CarProtocol public final class Suggestion {
+ method public android.app.PendingIntent? getAction();
+ method public androidx.car.app.model.CarIcon? getIcon();
+ method public String getIdentifier();
+ method public androidx.car.app.model.CarText? getSubtitle();
+ method public androidx.car.app.model.CarText getTitle();
+ }
+
+ public static final class Suggestion.Builder {
+ ctor public Suggestion.Builder();
+ method public androidx.car.app.suggestion.model.Suggestion build();
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setAction(android.app.PendingIntent);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setIcon(androidx.car.app.model.CarIcon);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setIdentifier(String);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setSubtitle(CharSequence);
+ method public androidx.car.app.suggestion.model.Suggestion.Builder setTitle(CharSequence);
+ }
+
+}
+
+package androidx.car.app.validation {
+
+ public final class HostValidator {
+ method public java.util.Map<java.lang.String!,java.util.List<java.lang.String!>!> getAllowedHosts();
+ method public boolean isValidHost(androidx.car.app.HostInfo);
+ field public static final androidx.car.app.validation.HostValidator ALLOW_ALL_HOSTS_VALIDATOR;
+ field public static final String TEMPLATE_RENDERER_PERMISSION = "android.car.permission.TEMPLATE_RENDERER";
+ }
+
+ public static final class HostValidator.Builder {
+ ctor public HostValidator.Builder(android.content.Context);
+ method public androidx.car.app.validation.HostValidator.Builder addAllowedHost(String, String);
+ method public androidx.car.app.validation.HostValidator.Builder addAllowedHosts(@ArrayRes int);
+ method public androidx.car.app.validation.HostValidator build();
+ }
+
+}
+
+package androidx.car.app.versioning {
+
+ public final class CarAppApiLevels {
+ method public static int getLatest();
+ method public static int getOldest();
+ field public static final int LEVEL_1 = 1; // 0x1
+ field public static final int LEVEL_2 = 2; // 0x2
+ field public static final int LEVEL_3 = 3; // 0x3
+ field public static final int LEVEL_4 = 4; // 0x4
+ field public static final int LEVEL_5 = 5; // 0x5
+ field public static final int LEVEL_6 = 6; // 0x6
+ field public static final int LEVEL_7 = 7; // 0x7
+ }
+
+}
+
diff --git a/car/app/app/api/restricted_current.txt b/car/app/app/api/restricted_current.txt
index 43d9cf5..73c12de 100644
--- a/car/app/app/api/restricted_current.txt
+++ b/car/app/app/api/restricted_current.txt
@@ -1055,11 +1055,13 @@
field public static final androidx.car.app.model.CarIcon ALERT;
field public static final androidx.car.app.model.CarIcon APP_ICON;
field public static final androidx.car.app.model.CarIcon BACK;
+ field @androidx.car.app.annotations.RequiresCarApi(7) public static final androidx.car.app.model.CarIcon COMPOSE_MESSAGE;
field public static final androidx.car.app.model.CarIcon ERROR;
field @androidx.car.app.annotations.RequiresCarApi(2) public static final androidx.car.app.model.CarIcon PAN;
field public static final int TYPE_ALERT = 4; // 0x4
field public static final int TYPE_APP_ICON = 5; // 0x5
field public static final int TYPE_BACK = 3; // 0x3
+ field public static final int TYPE_COMPOSE_MESSAGE = 8; // 0x8
field public static final int TYPE_CUSTOM = 1; // 0x1
field public static final int TYPE_ERROR = 6; // 0x6
field public static final int TYPE_PAN = 7; // 0x7
diff --git a/car/app/app/src/main/java/androidx/car/app/model/CarIcon.java b/car/app/app/src/main/java/androidx/car/app/model/CarIcon.java
index 8ec78e1..def03f3 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/CarIcon.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/CarIcon.java
@@ -30,10 +30,10 @@
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.car.app.annotations.CarProtocol;
+import androidx.car.app.annotations.KeepFields;
import androidx.car.app.annotations.RequiresCarApi;
import androidx.car.app.model.constraints.CarColorConstraints;
import androidx.car.app.model.constraints.CarIconConstraints;
-import androidx.car.app.annotations.KeepFields;
import androidx.core.graphics.drawable.IconCompat;
import java.lang.annotation.Retention;
@@ -113,6 +113,7 @@
TYPE_APP_ICON,
TYPE_ERROR,
TYPE_PAN,
+ TYPE_COMPOSE_MESSAGE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CarIconType {
@@ -159,6 +160,13 @@
public static final int TYPE_PAN = 7;
/**
+ * A compose message icon.
+ *
+ * @see #COMPOSE_MESSAGE
+ */
+ public static final int TYPE_COMPOSE_MESSAGE = 8;
+
+ /**
* Represents the app's icon, as defined in the app's manifest by the {@code android:icon}
* attribute of the {@code application} element.
*/
@@ -190,6 +198,13 @@
@NonNull
public static final CarIcon PAN = CarIcon.forStandardType(TYPE_PAN);
+ /**
+ * An icon representing a compose action.
+ */
+ @RequiresCarApi(7)
+ @NonNull
+ public static final CarIcon COMPOSE_MESSAGE = CarIcon.forStandardType(TYPE_COMPOSE_MESSAGE);
+
@CarIconType
private final int mType;
@Nullable
@@ -315,6 +330,8 @@
return "BACK";
case TYPE_PAN:
return "PAN";
+ case TYPE_COMPOSE_MESSAGE:
+ return "COMPOSE_MESSAGE";
case TYPE_CUSTOM:
return "CUSTOM";
default:
diff --git a/collection/collection-benchmark/build.gradle b/collection/collection-benchmark/build.gradle
index 931098c..11b20b6 100644
--- a/collection/collection-benchmark/build.gradle
+++ b/collection/collection-benchmark/build.gradle
@@ -65,12 +65,12 @@
androidTest {
dependsOn(commonTest)
dependencies {
- implementation(projectOrArtifact(":benchmark:benchmark-junit4"))
+ implementation("androidx.benchmark:benchmark-junit4:1.1.1")
implementation(libs.junit)
- implementation(libs.testExtJunit)
- implementation(libs.testCore)
- implementation(libs.testRunner)
- implementation(libs.testRules)
+ implementation("androidx.test.ext:junit:1.1.5")
+ implementation("androidx.test:core:1.5.0")
+ implementation("androidx.test:runner:1.5.2")
+ implementation("androidx.test:rules:1.5.0")
}
}
diff --git a/collection/collection-benchmark/src/androidTest/java/androidx/collection/ArraySetBenchmarkTest.kt b/collection/collection-benchmark/src/androidTest/java/androidx/collection/ArraySetBenchmarkTest.kt
index 1f38347..e80eb0a 100644
--- a/collection/collection-benchmark/src/androidTest/java/androidx/collection/ArraySetBenchmarkTest.kt
+++ b/collection/collection-benchmark/src/androidTest/java/androidx/collection/ArraySetBenchmarkTest.kt
@@ -17,6 +17,7 @@
package androidx.collection
import androidx.benchmark.junit4.BenchmarkRule
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,11 +41,13 @@
benchmark.runCollectionBenchmark(ArraySetContainsElementBenchmark(sourceSet))
}
+ @Ignore("b/293929098") // Flaky / failing in presubmit.
@Test
fun indexOf() {
benchmark.runCollectionBenchmark(ArraySetIndexOfBenchmark(sourceSet))
}
+ @Ignore("b/293929098") // Flaky / failing in presubmit.
@Test
fun addAllThenRemoveIndividually() {
benchmark.runCollectionBenchmark(ArraySetAddAllThenRemoveIndividuallyBenchmark(sourceSet))
diff --git a/collection/collection-ktx/api/1.3.0-beta01.txt b/collection/collection-ktx/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/collection/collection-ktx/api/1.3.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/collection/collection-ktx/api/restricted_1.3.0-beta01.txt b/collection/collection-ktx/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/collection/collection-ktx/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/collection/collection/api/1.3.0-beta01.txt b/collection/collection/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..a2fdada
--- /dev/null
+++ b/collection/collection/api/1.3.0-beta01.txt
@@ -0,0 +1,236 @@
+// Signature format: 4.0
+package androidx.collection {
+
+ public class ArrayMap<K, V> extends androidx.collection.SimpleArrayMap<K,V> implements java.util.Map<K,V> {
+ ctor public ArrayMap();
+ ctor public ArrayMap(androidx.collection.SimpleArrayMap?);
+ ctor public ArrayMap(int);
+ method public boolean containsAll(java.util.Collection<?>);
+ method public boolean containsKey(Object?);
+ method public boolean containsValue(Object?);
+ method public java.util.Set<java.util.Map.Entry<K!,V!>!> entrySet();
+ method public V! get(Object?);
+ method public java.util.Set<K!> keySet();
+ method public void putAll(java.util.Map<? extends K,? extends V>);
+ method public V! remove(Object?);
+ method public boolean removeAll(java.util.Collection<?>);
+ method public boolean retainAll(java.util.Collection<?>);
+ method public java.util.Collection<V!> values();
+ }
+
+ public final class ArrayMapKt {
+ method public static inline <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf();
+ method public static <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs);
+ }
+
+ public final class ArraySet<E> implements java.util.Collection<E> kotlin.jvm.internal.markers.KMutableCollection kotlin.jvm.internal.markers.KMutableSet java.util.Set<E> {
+ ctor public ArraySet();
+ ctor public ArraySet(androidx.collection.ArraySet<? extends E>? set);
+ ctor public ArraySet(E![]? array);
+ ctor public ArraySet(optional int capacity);
+ ctor public ArraySet(java.util.Collection<? extends E>? set);
+ method public boolean add(E element);
+ method public void addAll(androidx.collection.ArraySet<? extends E> array);
+ method public boolean addAll(java.util.Collection<? extends E> elements);
+ method public void clear();
+ method public operator boolean contains(E element);
+ method public boolean containsAll(java.util.Collection<E!> elements);
+ method public void ensureCapacity(int minimumCapacity);
+ method public int getSize();
+ method public int indexOf(Object? key);
+ method public boolean isEmpty();
+ method public java.util.Iterator<E> iterator();
+ method public boolean remove(E element);
+ method public boolean removeAll(androidx.collection.ArraySet<? extends E> array);
+ method public boolean removeAll(java.util.Collection<E!> elements);
+ method public E removeAt(int index);
+ method public boolean retainAll(java.util.Collection<E!> elements);
+ method public Object![] toArray();
+ method public <T> T![] toArray(T![] array);
+ method public E valueAt(int index);
+ property public int size;
+ }
+
+ public final class ArraySetKt {
+ method public static inline <T> androidx.collection.ArraySet<T> arraySetOf();
+ method public static <T> androidx.collection.ArraySet<T> arraySetOf(T?... values);
+ }
+
+ public final class CircularArray<E> {
+ ctor public CircularArray();
+ ctor public CircularArray(optional int minCapacity);
+ method public void addFirst(E element);
+ method public void addLast(E element);
+ method public void clear();
+ method public operator E get(int index);
+ method public E getFirst();
+ method public E getLast();
+ method public boolean isEmpty();
+ method public E popFirst();
+ method public E popLast();
+ method public void removeFromEnd(int count);
+ method public void removeFromStart(int count);
+ method public int size();
+ property public final E first;
+ property public final E last;
+ }
+
+ public final class CircularIntArray {
+ ctor public CircularIntArray();
+ ctor public CircularIntArray(optional int minCapacity);
+ method public void addFirst(int element);
+ method public void addLast(int element);
+ method public void clear();
+ method public operator int get(int index);
+ method public int getFirst();
+ method public int getLast();
+ method public boolean isEmpty();
+ method public int popFirst();
+ method public int popLast();
+ method public void removeFromEnd(int count);
+ method public void removeFromStart(int count);
+ method public int size();
+ property public final int first;
+ property public final int last;
+ }
+
+ public class LongSparseArray<E> implements java.lang.Cloneable {
+ ctor public LongSparseArray();
+ ctor public LongSparseArray(optional int initialCapacity);
+ method public void append(long key, E value);
+ method public void clear();
+ method public androidx.collection.LongSparseArray<E> clone();
+ method public boolean containsKey(long key);
+ method public boolean containsValue(E value);
+ method @Deprecated public void delete(long key);
+ method public operator E? get(long key);
+ method public E get(long key, E defaultValue);
+ method public int indexOfKey(long key);
+ method public int indexOfValue(E value);
+ method public boolean isEmpty();
+ method public long keyAt(int index);
+ method public void put(long key, E value);
+ method public void putAll(androidx.collection.LongSparseArray<? extends E> other);
+ method public E? putIfAbsent(long key, E value);
+ method public void remove(long key);
+ method public boolean remove(long key, E value);
+ method public void removeAt(int index);
+ method public E? replace(long key, E value);
+ method public boolean replace(long key, E oldValue, E newValue);
+ method public void setValueAt(int index, E value);
+ method public int size();
+ method public E valueAt(int index);
+ }
+
+ public final class LongSparseArrayKt {
+ method public static inline operator <T> boolean contains(androidx.collection.LongSparseArray<T>, long key);
+ method public static inline <T> void forEach(androidx.collection.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+ method public static inline <T> T getOrDefault(androidx.collection.LongSparseArray<T>, long key, T defaultValue);
+ method public static inline <T> T getOrElse(androidx.collection.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(androidx.collection.LongSparseArray<T>);
+ method public static inline <T> boolean isNotEmpty(androidx.collection.LongSparseArray<T>);
+ method public static <T> kotlin.collections.LongIterator keyIterator(androidx.collection.LongSparseArray<T>);
+ method public static operator <T> androidx.collection.LongSparseArray<T> plus(androidx.collection.LongSparseArray<T>, androidx.collection.LongSparseArray<T> other);
+ method @Deprecated public static <T> boolean remove(androidx.collection.LongSparseArray<T>, long key, T value);
+ method public static inline operator <T> void set(androidx.collection.LongSparseArray<T>, long key, T value);
+ method public static <T> java.util.Iterator<T> valueIterator(androidx.collection.LongSparseArray<T>);
+ }
+
+ public class LruCache<K, V> {
+ ctor public LruCache(@IntRange(from=1L, to=kotlin.jvm.internal.LongCompanionObject.MAX_VALUE) int maxSize);
+ method protected V? create(K key);
+ method public final int createCount();
+ method protected void entryRemoved(boolean evicted, K key, V oldValue, V? newValue);
+ method public final void evictAll();
+ method public final int evictionCount();
+ method public final operator V? get(K key);
+ method public final int hitCount();
+ method public final int maxSize();
+ method public final int missCount();
+ method public final V? put(K key, V value);
+ method public final int putCount();
+ method public final V? remove(K key);
+ method public void resize(@IntRange(from=1L, to=kotlin.jvm.internal.LongCompanionObject.MAX_VALUE) int maxSize);
+ method public final int size();
+ method protected int sizeOf(K key, V value);
+ method public final java.util.Map<K,V> snapshot();
+ method public void trimToSize(int maxSize);
+ }
+
+ public final class LruCacheKt {
+ method public static inline <K, V> androidx.collection.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+ }
+
+ public class SimpleArrayMap<K, V> {
+ ctor public SimpleArrayMap();
+ ctor public SimpleArrayMap(androidx.collection.SimpleArrayMap<? extends K,? extends V>? map);
+ ctor public SimpleArrayMap(optional int capacity);
+ method public void clear();
+ method public boolean containsKey(K key);
+ method public boolean containsValue(V value);
+ method public void ensureCapacity(int minimumCapacity);
+ method public operator V? get(K key);
+ method public V getOrDefault(Object? key, V defaultValue);
+ method public int indexOfKey(K key);
+ method public boolean isEmpty();
+ method public K keyAt(int index);
+ method public V? put(K key, V value);
+ method public void putAll(androidx.collection.SimpleArrayMap<? extends K,? extends V> map);
+ method public V? putIfAbsent(K key, V value);
+ method public V? remove(K key);
+ method public boolean remove(K key, V value);
+ method public V removeAt(int index);
+ method public V? replace(K key, V value);
+ method public boolean replace(K key, V oldValue, V newValue);
+ method public V setValueAt(int index, V value);
+ method public int size();
+ method public V valueAt(int index);
+ }
+
+ public class SparseArrayCompat<E> implements java.lang.Cloneable {
+ ctor public SparseArrayCompat();
+ ctor public SparseArrayCompat(optional int initialCapacity);
+ method public void append(int key, E value);
+ method public void clear();
+ method public androidx.collection.SparseArrayCompat<E> clone();
+ method public boolean containsKey(int key);
+ method public boolean containsValue(E value);
+ method @Deprecated public void delete(int key);
+ method public operator E? get(int key);
+ method public E get(int key, E defaultValue);
+ method public final boolean getIsEmpty();
+ method public int indexOfKey(int key);
+ method public int indexOfValue(E value);
+ method public boolean isEmpty();
+ method public int keyAt(int index);
+ method public void put(int key, E value);
+ method public void putAll(androidx.collection.SparseArrayCompat<? extends E> other);
+ method public E? putIfAbsent(int key, E value);
+ method public void remove(int key);
+ method public boolean remove(int key, Object? value);
+ method public void removeAt(int index);
+ method public void removeAtRange(int index, int size);
+ method public E? replace(int key, E value);
+ method public boolean replace(int key, E oldValue, E newValue);
+ method public void setValueAt(int index, E value);
+ method public int size();
+ method public E valueAt(int index);
+ property public final boolean isEmpty;
+ }
+
+ public final class SparseArrayKt {
+ method public static inline operator <T> boolean contains(androidx.collection.SparseArrayCompat<T>, int key);
+ method public static inline <T> void forEach(androidx.collection.SparseArrayCompat<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+ method public static inline <T> T getOrDefault(androidx.collection.SparseArrayCompat<T>, int key, T defaultValue);
+ method public static inline <T> T getOrElse(androidx.collection.SparseArrayCompat<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(androidx.collection.SparseArrayCompat<T>);
+ method public static inline <T> boolean isNotEmpty(androidx.collection.SparseArrayCompat<T>);
+ method public static <T> kotlin.collections.IntIterator keyIterator(androidx.collection.SparseArrayCompat<T>);
+ method public static operator <T> androidx.collection.SparseArrayCompat<T> plus(androidx.collection.SparseArrayCompat<T>, androidx.collection.SparseArrayCompat<T> other);
+ method @Deprecated public static <T> boolean remove(androidx.collection.SparseArrayCompat<T>, int key, T value);
+ method public static inline operator <T> void set(androidx.collection.SparseArrayCompat<T>, int key, T value);
+ method public static <T> java.util.Iterator<T> valueIterator(androidx.collection.SparseArrayCompat<T>);
+ }
+
+}
+
diff --git a/collection/collection/api/restricted_1.3.0-beta01.txt b/collection/collection/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..a2fdada
--- /dev/null
+++ b/collection/collection/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,236 @@
+// Signature format: 4.0
+package androidx.collection {
+
+ public class ArrayMap<K, V> extends androidx.collection.SimpleArrayMap<K,V> implements java.util.Map<K,V> {
+ ctor public ArrayMap();
+ ctor public ArrayMap(androidx.collection.SimpleArrayMap?);
+ ctor public ArrayMap(int);
+ method public boolean containsAll(java.util.Collection<?>);
+ method public boolean containsKey(Object?);
+ method public boolean containsValue(Object?);
+ method public java.util.Set<java.util.Map.Entry<K!,V!>!> entrySet();
+ method public V! get(Object?);
+ method public java.util.Set<K!> keySet();
+ method public void putAll(java.util.Map<? extends K,? extends V>);
+ method public V! remove(Object?);
+ method public boolean removeAll(java.util.Collection<?>);
+ method public boolean retainAll(java.util.Collection<?>);
+ method public java.util.Collection<V!> values();
+ }
+
+ public final class ArrayMapKt {
+ method public static inline <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf();
+ method public static <K, V> androidx.collection.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs);
+ }
+
+ public final class ArraySet<E> implements java.util.Collection<E> kotlin.jvm.internal.markers.KMutableCollection kotlin.jvm.internal.markers.KMutableSet java.util.Set<E> {
+ ctor public ArraySet();
+ ctor public ArraySet(androidx.collection.ArraySet<? extends E>? set);
+ ctor public ArraySet(E![]? array);
+ ctor public ArraySet(optional int capacity);
+ ctor public ArraySet(java.util.Collection<? extends E>? set);
+ method public boolean add(E element);
+ method public void addAll(androidx.collection.ArraySet<? extends E> array);
+ method public boolean addAll(java.util.Collection<? extends E> elements);
+ method public void clear();
+ method public operator boolean contains(E element);
+ method public boolean containsAll(java.util.Collection<E!> elements);
+ method public void ensureCapacity(int minimumCapacity);
+ method public int getSize();
+ method public int indexOf(Object? key);
+ method public boolean isEmpty();
+ method public java.util.Iterator<E> iterator();
+ method public boolean remove(E element);
+ method public boolean removeAll(androidx.collection.ArraySet<? extends E> array);
+ method public boolean removeAll(java.util.Collection<E!> elements);
+ method public E removeAt(int index);
+ method public boolean retainAll(java.util.Collection<E!> elements);
+ method public Object![] toArray();
+ method public <T> T![] toArray(T![] array);
+ method public E valueAt(int index);
+ property public int size;
+ }
+
+ public final class ArraySetKt {
+ method public static inline <T> androidx.collection.ArraySet<T> arraySetOf();
+ method public static <T> androidx.collection.ArraySet<T> arraySetOf(T?... values);
+ }
+
+ public final class CircularArray<E> {
+ ctor public CircularArray();
+ ctor public CircularArray(optional int minCapacity);
+ method public void addFirst(E element);
+ method public void addLast(E element);
+ method public void clear();
+ method public operator E get(int index);
+ method public E getFirst();
+ method public E getLast();
+ method public boolean isEmpty();
+ method public E popFirst();
+ method public E popLast();
+ method public void removeFromEnd(int count);
+ method public void removeFromStart(int count);
+ method public int size();
+ property public final E first;
+ property public final E last;
+ }
+
+ public final class CircularIntArray {
+ ctor public CircularIntArray();
+ ctor public CircularIntArray(optional int minCapacity);
+ method public void addFirst(int element);
+ method public void addLast(int element);
+ method public void clear();
+ method public operator int get(int index);
+ method public int getFirst();
+ method public int getLast();
+ method public boolean isEmpty();
+ method public int popFirst();
+ method public int popLast();
+ method public void removeFromEnd(int count);
+ method public void removeFromStart(int count);
+ method public int size();
+ property public final int first;
+ property public final int last;
+ }
+
+ public class LongSparseArray<E> implements java.lang.Cloneable {
+ ctor public LongSparseArray();
+ ctor public LongSparseArray(optional int initialCapacity);
+ method public void append(long key, E value);
+ method public void clear();
+ method public androidx.collection.LongSparseArray<E> clone();
+ method public boolean containsKey(long key);
+ method public boolean containsValue(E value);
+ method @Deprecated public void delete(long key);
+ method public operator E? get(long key);
+ method public E get(long key, E defaultValue);
+ method public int indexOfKey(long key);
+ method public int indexOfValue(E value);
+ method public boolean isEmpty();
+ method public long keyAt(int index);
+ method public void put(long key, E value);
+ method public void putAll(androidx.collection.LongSparseArray<? extends E> other);
+ method public E? putIfAbsent(long key, E value);
+ method public void remove(long key);
+ method public boolean remove(long key, E value);
+ method public void removeAt(int index);
+ method public E? replace(long key, E value);
+ method public boolean replace(long key, E oldValue, E newValue);
+ method public void setValueAt(int index, E value);
+ method public int size();
+ method public E valueAt(int index);
+ }
+
+ public final class LongSparseArrayKt {
+ method public static inline operator <T> boolean contains(androidx.collection.LongSparseArray<T>, long key);
+ method public static inline <T> void forEach(androidx.collection.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+ method public static inline <T> T getOrDefault(androidx.collection.LongSparseArray<T>, long key, T defaultValue);
+ method public static inline <T> T getOrElse(androidx.collection.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(androidx.collection.LongSparseArray<T>);
+ method public static inline <T> boolean isNotEmpty(androidx.collection.LongSparseArray<T>);
+ method public static <T> kotlin.collections.LongIterator keyIterator(androidx.collection.LongSparseArray<T>);
+ method public static operator <T> androidx.collection.LongSparseArray<T> plus(androidx.collection.LongSparseArray<T>, androidx.collection.LongSparseArray<T> other);
+ method @Deprecated public static <T> boolean remove(androidx.collection.LongSparseArray<T>, long key, T value);
+ method public static inline operator <T> void set(androidx.collection.LongSparseArray<T>, long key, T value);
+ method public static <T> java.util.Iterator<T> valueIterator(androidx.collection.LongSparseArray<T>);
+ }
+
+ public class LruCache<K, V> {
+ ctor public LruCache(@IntRange(from=1L, to=kotlin.jvm.internal.LongCompanionObject.MAX_VALUE) int maxSize);
+ method protected V? create(K key);
+ method public final int createCount();
+ method protected void entryRemoved(boolean evicted, K key, V oldValue, V? newValue);
+ method public final void evictAll();
+ method public final int evictionCount();
+ method public final operator V? get(K key);
+ method public final int hitCount();
+ method public final int maxSize();
+ method public final int missCount();
+ method public final V? put(K key, V value);
+ method public final int putCount();
+ method public final V? remove(K key);
+ method public void resize(@IntRange(from=1L, to=kotlin.jvm.internal.LongCompanionObject.MAX_VALUE) int maxSize);
+ method public final int size();
+ method protected int sizeOf(K key, V value);
+ method public final java.util.Map<K,V> snapshot();
+ method public void trimToSize(int maxSize);
+ }
+
+ public final class LruCacheKt {
+ method public static inline <K, V> androidx.collection.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+ }
+
+ public class SimpleArrayMap<K, V> {
+ ctor public SimpleArrayMap();
+ ctor public SimpleArrayMap(androidx.collection.SimpleArrayMap<? extends K,? extends V>? map);
+ ctor public SimpleArrayMap(optional int capacity);
+ method public void clear();
+ method public boolean containsKey(K key);
+ method public boolean containsValue(V value);
+ method public void ensureCapacity(int minimumCapacity);
+ method public operator V? get(K key);
+ method public V getOrDefault(Object? key, V defaultValue);
+ method public int indexOfKey(K key);
+ method public boolean isEmpty();
+ method public K keyAt(int index);
+ method public V? put(K key, V value);
+ method public void putAll(androidx.collection.SimpleArrayMap<? extends K,? extends V> map);
+ method public V? putIfAbsent(K key, V value);
+ method public V? remove(K key);
+ method public boolean remove(K key, V value);
+ method public V removeAt(int index);
+ method public V? replace(K key, V value);
+ method public boolean replace(K key, V oldValue, V newValue);
+ method public V setValueAt(int index, V value);
+ method public int size();
+ method public V valueAt(int index);
+ }
+
+ public class SparseArrayCompat<E> implements java.lang.Cloneable {
+ ctor public SparseArrayCompat();
+ ctor public SparseArrayCompat(optional int initialCapacity);
+ method public void append(int key, E value);
+ method public void clear();
+ method public androidx.collection.SparseArrayCompat<E> clone();
+ method public boolean containsKey(int key);
+ method public boolean containsValue(E value);
+ method @Deprecated public void delete(int key);
+ method public operator E? get(int key);
+ method public E get(int key, E defaultValue);
+ method public final boolean getIsEmpty();
+ method public int indexOfKey(int key);
+ method public int indexOfValue(E value);
+ method public boolean isEmpty();
+ method public int keyAt(int index);
+ method public void put(int key, E value);
+ method public void putAll(androidx.collection.SparseArrayCompat<? extends E> other);
+ method public E? putIfAbsent(int key, E value);
+ method public void remove(int key);
+ method public boolean remove(int key, Object? value);
+ method public void removeAt(int index);
+ method public void removeAtRange(int index, int size);
+ method public E? replace(int key, E value);
+ method public boolean replace(int key, E oldValue, E newValue);
+ method public void setValueAt(int index, E value);
+ method public int size();
+ method public E valueAt(int index);
+ property public final boolean isEmpty;
+ }
+
+ public final class SparseArrayKt {
+ method public static inline operator <T> boolean contains(androidx.collection.SparseArrayCompat<T>, int key);
+ method public static inline <T> void forEach(androidx.collection.SparseArrayCompat<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+ method public static inline <T> T getOrDefault(androidx.collection.SparseArrayCompat<T>, int key, T defaultValue);
+ method public static inline <T> T getOrElse(androidx.collection.SparseArrayCompat<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+ method public static inline <T> int getSize(androidx.collection.SparseArrayCompat<T>);
+ method public static inline <T> boolean isNotEmpty(androidx.collection.SparseArrayCompat<T>);
+ method public static <T> kotlin.collections.IntIterator keyIterator(androidx.collection.SparseArrayCompat<T>);
+ method public static operator <T> androidx.collection.SparseArrayCompat<T> plus(androidx.collection.SparseArrayCompat<T>, androidx.collection.SparseArrayCompat<T> other);
+ method @Deprecated public static <T> boolean remove(androidx.collection.SparseArrayCompat<T>, int key, T value);
+ method public static inline operator <T> void set(androidx.collection.SparseArrayCompat<T>, int key, T value);
+ method public static <T> java.util.Iterator<T> valueIterator(androidx.collection.SparseArrayCompat<T>);
+ }
+
+}
+
diff --git a/compose/animation/animation/api/current.ignore b/compose/animation/animation/api/current.ignore
new file mode 100644
index 0000000..721c745
--- /dev/null
+++ b/compose/animation/animation/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+AddedAbstractMethod: androidx.compose.animation.AnimatedContentTransitionScope#getContentAlignment():
+ Added method androidx.compose.animation.AnimatedContentTransitionScope.getContentAlignment()
diff --git a/compose/animation/animation/api/current.txt b/compose/animation/animation/api/current.txt
index f66083e..1d1e078 100644
--- a/compose/animation/animation/api/current.txt
+++ b/compose/animation/animation/api/current.txt
@@ -17,10 +17,14 @@
}
public sealed interface AnimatedContentTransitionScope<S> extends androidx.compose.animation.core.Transition.Segment<S> {
+ method public androidx.compose.ui.Alignment getContentAlignment();
method public default androidx.compose.animation.ExitTransition getHold(androidx.compose.animation.ExitTransition.Companion);
+ method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.EnterTransition scaleInToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
+ method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.ExitTransition scaleOutToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
method public androidx.compose.animation.EnterTransition slideIntoContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialOffset);
method public androidx.compose.animation.ExitTransition slideOutOfContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> targetOffset);
method public infix androidx.compose.animation.ContentTransform using(androidx.compose.animation.ContentTransform, androidx.compose.animation.SizeTransform? sizeTransform);
+ property public abstract androidx.compose.ui.Alignment contentAlignment;
}
@androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public static final value class AnimatedContentTransitionScope.SlideDirection {
diff --git a/compose/animation/animation/api/restricted_current.ignore b/compose/animation/animation/api/restricted_current.ignore
new file mode 100644
index 0000000..721c745
--- /dev/null
+++ b/compose/animation/animation/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+AddedAbstractMethod: androidx.compose.animation.AnimatedContentTransitionScope#getContentAlignment():
+ Added method androidx.compose.animation.AnimatedContentTransitionScope.getContentAlignment()
diff --git a/compose/animation/animation/api/restricted_current.txt b/compose/animation/animation/api/restricted_current.txt
index f66083e..1d1e078 100644
--- a/compose/animation/animation/api/restricted_current.txt
+++ b/compose/animation/animation/api/restricted_current.txt
@@ -17,10 +17,14 @@
}
public sealed interface AnimatedContentTransitionScope<S> extends androidx.compose.animation.core.Transition.Segment<S> {
+ method public androidx.compose.ui.Alignment getContentAlignment();
method public default androidx.compose.animation.ExitTransition getHold(androidx.compose.animation.ExitTransition.Companion);
+ method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.EnterTransition scaleInToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
+ method @SuppressCompatibility @androidx.compose.animation.ExperimentalAnimationApi public androidx.compose.animation.ExitTransition scaleOutToFitContainer(optional androidx.compose.ui.Alignment alignment, optional androidx.compose.ui.layout.ContentScale contentScale);
method public androidx.compose.animation.EnterTransition slideIntoContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> initialOffset);
method public androidx.compose.animation.ExitTransition slideOutOfContainer(int towards, optional androidx.compose.animation.core.FiniteAnimationSpec<androidx.compose.ui.unit.IntOffset> animationSpec, optional kotlin.jvm.functions.Function1<? super java.lang.Integer,java.lang.Integer> targetOffset);
method public infix androidx.compose.animation.ContentTransform using(androidx.compose.animation.ContentTransform, androidx.compose.animation.SizeTransform? sizeTransform);
+ property public abstract androidx.compose.ui.Alignment contentAlignment;
}
@androidx.compose.runtime.Immutable @kotlin.jvm.JvmInline public static final value class AnimatedContentTransitionScope.SlideDirection {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt
new file mode 100644
index 0000000..e2bbcbd
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/layoutanimation/ContainerTransform.kt
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.animation.demos.layoutanimation
+
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateIntAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Icon
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.RadioButton
+import androidx.compose.material.Text
+import androidx.compose.material.TextField
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.AccountCircle
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+@OptIn(ExperimentalAnimationApi::class)
+@Preview
+@Composable
+fun LocalContainerTransformDemo() {
+ Box(Modifier.fillMaxSize()) {
+ LazyColumn {
+ items(20) {
+ Box(
+ Modifier
+ .fillMaxWidth()
+ .height(150.dp)
+ .padding(15.dp)
+ .background(MaterialTheme.colors.primary)
+ )
+ }
+ }
+ }
+ var selectedAlignment by remember { mutableStateOf(Alignment.Center) }
+ var contentScale by remember { mutableStateOf(ContentScale.FillWidth) }
+ Column(
+ Modifier.padding(top = 100.dp)
+ ) {
+ Column(
+ Modifier
+ .background(Color.LightGray, RoundedCornerShape(10.dp)),
+ ) {
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+ RadioButton(
+ selected = selectedAlignment == Alignment.TopStart,
+ onClick = { selectedAlignment = Alignment.TopStart }
+ )
+ Text("TopStart", Modifier.padding(5.dp))
+ RadioButton(
+ selected = selectedAlignment == Alignment.TopCenter,
+ onClick = { selectedAlignment = Alignment.TopCenter }
+ )
+ Text("TopCenter", Modifier.padding(5.dp))
+ RadioButton(
+ selected = selectedAlignment == Alignment.TopEnd,
+ onClick = { selectedAlignment = Alignment.TopEnd }
+ )
+ Text("TopEnd", Modifier.padding(5.dp))
+ }
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+ RadioButton(
+ selected = selectedAlignment == Alignment.CenterStart,
+ onClick = { selectedAlignment = Alignment.CenterStart }
+ )
+ Text("CenterStart", Modifier.padding(5.dp))
+ RadioButton(
+ selected = selectedAlignment == Alignment.Center,
+ onClick = { selectedAlignment = Alignment.Center }
+ )
+ Text("Center", Modifier.padding(5.dp))
+ RadioButton(
+ selected = selectedAlignment == Alignment.CenterEnd,
+ onClick = { selectedAlignment = Alignment.CenterEnd }
+ )
+ Text("CenterEnd", Modifier.padding(5.dp))
+ }
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+ RadioButton(
+ selected = selectedAlignment == Alignment.BottomStart,
+ onClick = { selectedAlignment = Alignment.BottomStart }
+ )
+ Text("BottomStart", Modifier.padding(5.dp))
+ RadioButton(
+ selected = selectedAlignment == Alignment.BottomCenter,
+ onClick = { selectedAlignment = Alignment.BottomCenter }
+ )
+ Text("BottomCenter", Modifier.padding(5.dp))
+ RadioButton(
+ selected = selectedAlignment == Alignment.BottomEnd,
+ onClick = { selectedAlignment = Alignment.BottomEnd }
+ )
+ Text("BottomEnd", Modifier.padding(5.dp))
+ }
+ }
+ Column(
+ Modifier
+ .background(Color.Gray, RoundedCornerShape(10.dp)),
+ ) {
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+ RadioButton(
+ selected = contentScale == ContentScale.FillWidth,
+ onClick = { contentScale = ContentScale.FillWidth }
+ )
+ Text("FillWidth", Modifier.padding(5.dp))
+ RadioButton(
+ selected = contentScale == ContentScale.FillHeight,
+ onClick = { contentScale = ContentScale.FillHeight }
+ )
+ Text("FillHeight", Modifier.padding(5.dp))
+ RadioButton(
+ selected = contentScale == ContentScale.FillBounds,
+ onClick = { contentScale = ContentScale.FillBounds }
+ )
+ Text("FillBounds", Modifier.padding(5.dp))
+ }
+ Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+ RadioButton(
+ selected = contentScale == ContentScale.Crop,
+ onClick = { contentScale = ContentScale.Crop }
+ )
+ Text("Crop", Modifier.padding(5.dp))
+ RadioButton(
+ selected = contentScale == ContentScale.Fit,
+ onClick = { contentScale = ContentScale.Fit }
+ )
+ Text("Fit", Modifier.padding(5.dp))
+ RadioButton(
+ selected = contentScale == ContentScale.Inside,
+ onClick = { contentScale = ContentScale.Inside }
+ )
+ Text("Inside", Modifier.padding(5.dp))
+ }
+ }
+ }
+ Box(Modifier.fillMaxSize()) {
+ var target by remember { mutableStateOf(ContainerState.FAB) }
+ // Corner radius
+ val cr by animateIntAsState(if (target == ContainerState.FAB) 50 else 0)
+ val padding by animateDpAsState(if (target == ContainerState.FAB) 10.dp else 0.dp)
+ AnimatedContent(
+ target,
+ label = "",
+ transitionSpec = {
+ fadeIn(tween(200, delayMillis = 100)) +
+ scaleInToFitContainer(selectedAlignment, contentScale) togetherWith
+ fadeOut(tween(100)) + scaleOutToFitContainer(selectedAlignment, contentScale)
+ },
+ modifier = Modifier
+ .align(Alignment.BottomEnd)
+ .padding(padding)
+ .clip(RoundedCornerShape(cr))
+ .background(Color.White)
+ ) {
+ if (it == ContainerState.FAB) {
+ Icon(
+ rememberVectorPainter(image = Icons.Default.Add),
+ null,
+ modifier = Modifier
+ .clickable {
+ target = ContainerState.FullScreen
+ }
+ .padding(20.dp))
+ } else {
+ Column(Modifier.fillMaxSize()) {
+ Icon(
+ rememberVectorPainter(image = Icons.Default.ArrowBack),
+ null,
+ modifier = Modifier
+ .clickable {
+ target = ContainerState.FAB
+ }
+ .padding(20.dp))
+ Spacer(Modifier.height(60.dp))
+ Text("Page Title", fontSize = 20.sp, modifier = Modifier.padding(20.dp))
+ Spacer(
+ Modifier
+ .fillMaxWidth()
+ .height(2.dp)
+ .background(Color.LightGray)
+ )
+ Row(
+ Modifier
+ .fillMaxWidth()
+ .padding(20.dp)
+ ) {
+ Icon(rememberVectorPainter(image = Icons.Default.AccountCircle), null)
+ Spacer(Modifier.width(20.dp))
+ TextField(value = "Account Name", onValueChange = {})
+ }
+ }
+ }
+ }
+ }
+}
+
+private enum class ContainerState {
+ FAB,
+ FullScreen
+}
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
index 96a707a..707240c 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/AnimateBoundsModifier.kt
@@ -33,7 +33,11 @@
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
+import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.intermediateLayout
@@ -54,6 +58,7 @@
Spring.DampingRatioNoBouncy,
Spring.StiffnessMediumLow
),
+ debug: Boolean = false,
lookaheadScope: (closestLookaheadScope: LookaheadScope) -> LookaheadScope = { it }
) = composed {
@@ -68,6 +73,17 @@
// When the measure block is invoked after lookahead pass, the lookahead size of the
// child will be accessible as a parameter to the measure block.
this
+ .drawWithContent {
+ drawContent()
+ if (debug) {
+ val offset = outerOffsetAnimation.target!! - outerOffsetAnimation.value!!
+ translate(
+ offset.x.toFloat(), offset.y.toFloat()
+ ) {
+ drawRect(Color.Black.copy(alpha = 0.5f), style = Stroke(10f))
+ }
+ }
+ }
.intermediateLayout { measurable, constraints ->
val (w, h) = outerSizeAnimation.updateTarget(
lookaheadSize,
@@ -85,6 +101,17 @@
}
}
.then(modifier)
+ .drawWithContent {
+ drawContent()
+ if (debug) {
+ val offset = offsetAnimation.target!! - offsetAnimation.value!!
+ translate(
+ offset.x.toFloat(), offset.y.toFloat()
+ ) {
+ drawRect(Color.Green.copy(alpha = 0.5f), style = Stroke(10f))
+ }
+ }
+ }
.intermediateLayout { measurable, _ ->
// When layout changes, the lookahead pass will calculate a new final size for the
// child modifier. This lookahead size can be used to animate the size
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
index adba4fa..35058df 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/lookahead/LookaheadWithFlowRowDemo.kt
@@ -16,18 +16,26 @@
package androidx.compose.animation.demos.lookahead
+import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowColumn
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.Text
@@ -41,6 +49,8 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.LookaheadScope
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalComposeUiApi::class, ExperimentalLayoutApi::class)
@@ -135,6 +145,77 @@
}
}
+@OptIn(ExperimentalComposeUiApi::class, ExperimentalLayoutApi::class)
+@Preview
+@Composable
+fun NestedFlowRowDemo() {
+ LookaheadScope {
+ FlowRow(
+ modifier = Modifier.fillMaxSize(),
+ horizontalArrangement = Arrangement.Center,
+ verticalArrangement = Arrangement.Center,
+ maxItemsInEachRow = 3
+ ) {
+ var expanded by remember {
+ mutableStateOf(false)
+ }
+ Box(
+ modifier = Modifier
+ .animateBounds(Modifier.widthIn(max = 600.dp))
+ .background(Color.Red)
+ ) {
+ val height = animateDpAsState(targetValue = if (expanded) 500.dp else 300.dp)
+ Box(
+ modifier = Modifier
+ .animateBounds(
+ Modifier
+ .fillMaxWidth()
+ .height(height.value)
+ )
+ .clickable {
+ expanded = !expanded
+ })
+ }
+
+ FlowColumn(Modifier.layout { measurable, constraints ->
+ measurable.measure(constraints).run {
+ layout(width, height) {
+ place(0, 0)
+ }
+ }
+ }) {
+ Box(
+ modifier = Modifier
+ .size(200.dp)
+ .animateBounds(
+ Modifier
+ .wrapContentWidth()
+ .heightIn(min = 156.dp),
+ debug = true
+
+ )
+ .background(Color.Blue)
+ ) {
+ Box(modifier = Modifier.size(200.dp))
+ }
+ Box(
+ modifier = Modifier
+ .size(200.dp)
+ .animateBounds(
+ Modifier
+ .wrapContentWidth()
+ .heightIn(min = 156.dp),
+ debug = true
+ )
+ .background(Color.Yellow)
+ ) {
+ Box(modifier = Modifier.size(200.dp))
+ }
+ }
+ }
+ }
+}
+
private val colors = listOf(
Color(0xffff6f69),
Color(0xffffcc5c),
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
index f21c93f..f0e325b 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedContentSamples.kt
@@ -22,6 +22,7 @@
import androidx.compose.animation.AnimatedContentTransitionScope.SlideDirection
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.ExitTransition
+import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.keyframes
@@ -54,6 +55,7 @@
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -116,7 +118,8 @@
Box(
Modifier
.size(200.dp)
- .background(Color(0xffffdb00)))
+ .background(Color(0xffffdb00))
+ )
}
@Composable
@@ -124,7 +127,8 @@
Box(
Modifier
.size(40.dp)
- .background(Color(0xffff8100)))
+ .background(Color(0xffff8100))
+ )
}
@Composable
@@ -132,7 +136,8 @@
Box(
Modifier
.size(80.dp, 20.dp)
- .background(Color(0xffff4400)))
+ .background(Color(0xffff4400))
+ )
}
var contentState: ContentState by remember { mutableStateOf(ContentState.Foo) }
@@ -304,6 +309,30 @@
}
}
+@OptIn(ExperimentalAnimationApi::class)
+@Suppress("UNUSED_VARIABLE")
+@Sampled
+@Composable
+fun ScaleInToFitContainerSample() {
+ // enum class CartState { Expanded, Collapsed }
+ // This is an example of scaling both the incoming content and outgoing content to fit in the
+ // animating container size while animating alpha.
+ val transitionSpec: AnimatedContentTransitionScope<CartState>.() -> ContentTransform = {
+ // Fade in while scaling the content.
+ fadeIn() + scaleInToFitContainer() togetherWith
+ // Fade out outgoing content while scaling it. It is important
+ // to combine `scaleOutToFitContainer` with another ExitTransition that defines
+ // a timeframe for the exit (such as fade/shrink/slide/Hold).
+ fadeOut() + scaleOutToFitContainer(
+ // Default alignment is the content alignment defined in AnimatedContent
+ Alignment.Center,
+ // Content will be scaled based on the height of the content. Default content
+ // scale is ContentScale.FillWidth.
+ ContentScale.FillHeight
+ )
+ }
+}
+
private enum class CartState {
Expanded,
Collapsed
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
index 9540bd4..c6925f9 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedContentTest.kt
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalAnimationApi::class)
+
package androidx.compose.animation
import androidx.compose.animation.core.InternalAnimationApi
@@ -41,11 +43,16 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.boundsInRoot
import androidx.compose.ui.layout.onGloballyPositioned
+import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
@@ -54,6 +61,7 @@
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.round
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.google.common.truth.Truth.assertThat
@@ -656,6 +664,400 @@
assertTrue(box2EnterFinished)
}
+ @Test
+ fun testScaleToFitDefault() {
+ var target by mutableStateOf(1)
+ var box1Coords: LayoutCoordinates? = null
+ var box2Coords: LayoutCoordinates? = null
+ var box1Disposed = true
+ var box2Disposed = true
+ rule.setContent {
+ CompositionLocalProvider(LocalDensity provides Density(1f)) {
+ AnimatedContent(
+ targetState = target,
+ transitionSpec = {
+ if (1 isTransitioningTo 2) {
+ fadeIn(tween(300)) + scaleInToFitContainer() togetherWith
+ scaleOutToFitContainer()
+ } else {
+ fadeIn() + scaleInToFitContainer() togetherWith
+ fadeOut(tween(150))
+ } using SizeTransform { initialSize, targetSize ->
+ keyframes {
+ durationMillis = 300
+ initialSize at 100 with LinearEasing
+ targetSize at 200 with LinearEasing
+ }
+ }
+ }) {
+ if (it == 1) {
+ Box(
+ Modifier
+ .onPlaced {
+ box1Coords = it
+ }
+ .size(200.dp, 400.dp)) {
+ DisposableEffect(key1 = Unit) {
+ box1Disposed = false
+ onDispose {
+ box1Disposed = true
+ }
+ }
+ }
+ } else {
+ Box(
+ Modifier
+ .onPlaced { box2Coords = it }
+ .size(100.dp, 50.dp)) {
+
+ DisposableEffect(key1 = Unit) {
+ box2Disposed = false
+ onDispose {
+ box2Disposed = true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ rule.waitForIdle()
+ rule.mainClock.autoAdvance = false
+ assertEquals(IntSize(200, 400), box1Coords?.size)
+ assertNull(box2Coords)
+
+ assertFalse(box1Disposed)
+ assertTrue(box2Disposed)
+
+ rule.runOnIdle {
+ // Start transition from 1 -> 2, size 200,400 -> 100,50
+ target = 2
+ }
+ rule.mainClock.advanceTimeByFrame()
+ rule.waitForIdle()
+
+ // Box1 doesn't have any other ExitTransition than scale, so it'll be disposed
+ // after a couple of frames
+ assertFalse(box1Disposed)
+ assertFalse(box2Disposed)
+
+ repeat(20) {
+ rule.mainClock.advanceTimeByFrame()
+
+ val playTime = 16 * it
+ val bounds2 = box2Coords?.boundsInRoot()
+ if (playTime <= 100) {
+ assertEquals(Rect(0f, 0f, 200f, 100f), bounds2)
+ } else if (playTime <= 200) {
+ val fraction = (playTime - 100) / 100f
+ val width = 200 * (1 - fraction) + 100 * fraction
+ // Since we are testing default behavior, the scaling is based on width.
+ val height = width / 100f * 50
+ assertEquals(Offset.Zero, bounds2?.topLeft)
+ assertEquals(width, bounds2?.width)
+ assertEquals(height, bounds2?.height)
+ } else {
+ assertEquals(Rect(0f, 0f, 100f, 50f), bounds2)
+ }
+ }
+
+ rule.runOnIdle {
+ // Start transition from false -> true, size 100, 50 -> 200,400
+ target = 1
+ }
+ rule.mainClock.advanceTimeByFrame()
+ rule.waitForIdle()
+
+ assertFalse(box1Disposed)
+ assertFalse(box2Disposed)
+
+ repeat(20) {
+ rule.mainClock.advanceTimeByFrame()
+ val playTime = 16 * it
+ val bounds = box1Coords?.boundsInRoot()
+ if (playTime <= 100) {
+ assertEquals(100f, bounds?.width)
+ assertFalse(box2Disposed)
+ } else if (playTime <= 150) {
+ val fraction = (playTime - 100) / 100f
+ val width = 100 * (1 - fraction) + 200 * fraction
+ // Since we are testing default behavior, the scaling is based on width.
+ assertEquals(Offset.Zero, bounds?.topLeft)
+ assertEquals(width, bounds?.width)
+ } else {
+ rule.waitForIdle()
+ assertThat(box2Disposed)
+ }
+ }
+ }
+
+ @Test
+ fun testScaleToFitCenterAlignment() {
+ var target by mutableStateOf(true)
+ var box1Coords: LayoutCoordinates? = null
+ var box2Coords: LayoutCoordinates? = null
+ var layoutDirection: LayoutDirection? = null
+ rule.setContent {
+ CompositionLocalProvider(LocalDensity provides Density(1f)) {
+ layoutDirection = LocalLayoutDirection.current
+ AnimatedContent(
+ targetState = target,
+ transitionSpec = {
+ fadeIn() + scaleInToFitContainer(Alignment.Center) togetherWith
+ fadeOut(tween(100)) using
+ SizeTransform { _, _ ->
+ tween(100, easing = LinearEasing)
+ }
+ }) {
+ if (target) {
+ Box(
+ Modifier
+ .onPlaced {
+ box1Coords = it
+ }
+ .size(200.dp, 400.dp))
+ } else {
+ Box(
+ Modifier
+ .onPlaced { box2Coords = it }
+ .size(100.dp, 50.dp))
+ }
+ }
+ }
+ }
+
+ rule.waitForIdle()
+ assertEquals(IntSize(200, 400), box1Coords?.size)
+ assertNull(box2Coords)
+
+ rule.runOnIdle {
+ // Start transition from true -> false, size 200,400 -> 100,50
+ target = false
+ }
+ rule.mainClock.advanceTimeByFrame()
+ repeat(10) {
+ rule.mainClock.advanceTimeByFrame()
+ val playTime = 16 * it
+ val bounds = box2Coords?.boundsInRoot()
+ assertNotNull(bounds)
+ val fraction = (playTime / 100f).coerceAtMost(1f)
+ val width = 200 * (1 - fraction) + 100 * fraction
+ val containerHeight = 400 * (1 - fraction) + 50 * fraction
+ // Since we are testing default behavior, the scaling is based on width.
+ val height = width / 100f * 50
+ assertEquals(width, bounds!!.width, 0.01f)
+ assertEquals(height, bounds.height, 0.01f)
+ val offset = Alignment.Center.align(
+ IntSize(width.roundToInt(), height.roundToInt()),
+ IntSize(width.roundToInt(), containerHeight.roundToInt()), layoutDirection!!
+ )
+ assertEquals(offset, bounds.topLeft.round())
+ }
+ }
+
+ @Test
+ fun testScaleToFitBottomCenterAlignment() {
+ var target by mutableStateOf(true)
+ var box1Coords: LayoutCoordinates? = null
+ var box2Coords: LayoutCoordinates? = null
+ var layoutDirection: LayoutDirection? = null
+ rule.setContent {
+ CompositionLocalProvider(LocalDensity provides Density(1f)) {
+ layoutDirection = LocalLayoutDirection.current
+ AnimatedContent(
+ targetState = target,
+ transitionSpec = {
+ fadeIn() + scaleInToFitContainer(
+ Alignment.BottomCenter
+ ) togetherWith
+ fadeOut(tween(100)) using
+ SizeTransform { _, _ ->
+ tween(100, easing = LinearEasing)
+ }
+ }) {
+ if (target) {
+ Box(
+ Modifier
+ .onPlaced {
+ box1Coords = it
+ }
+ .size(200.dp, 400.dp))
+ } else {
+ Box(
+ Modifier
+ .onPlaced { box2Coords = it }
+ .size(100.dp, 50.dp))
+ }
+ }
+ }
+ }
+
+ rule.waitForIdle()
+ rule.mainClock.autoAdvance = false
+ assertEquals(IntSize(200, 400), box1Coords?.size)
+ assertNull(box2Coords)
+
+ rule.runOnIdle {
+ // Start transition from true -> false, size 200,400 -> 100,50
+ target = false
+ }
+ rule.mainClock.advanceTimeByFrame()
+ repeat(10) {
+ rule.mainClock.advanceTimeByFrame()
+ val playTime = 16 * it
+ val bounds = box2Coords?.boundsInRoot()
+ assertNotNull(bounds)
+ val fraction = (playTime / 100f).coerceAtMost(1f)
+ val width = 200 * (1 - fraction) + 100 * fraction
+ val containerHeight = 400 * (1 - fraction) + 50 * fraction
+ // Since we are testing default behavior, the scaling is based on width.
+ val height = width / 100f * 50
+ assertEquals(width, bounds!!.width, 0.01f)
+ assertEquals(height, bounds.height, 0.01f)
+ val offset = Alignment.BottomCenter.align(
+ IntSize(width.roundToInt(), height.roundToInt()),
+ IntSize(width.roundToInt(), containerHeight.roundToInt()), layoutDirection!!
+ )
+ assertEquals(offset, bounds.topLeft.round())
+ }
+ }
+
+ @Test
+ fun testScaleToFitInsideBottomEndAlignment() {
+ var target by mutableStateOf(true)
+ var box1Coords: LayoutCoordinates? = null
+ var box2Coords: LayoutCoordinates? = null
+ var layoutDirection: LayoutDirection? = null
+ rule.setContent {
+ CompositionLocalProvider(LocalDensity provides Density(1f)) {
+ layoutDirection = LocalLayoutDirection.current
+ AnimatedContent(
+ targetState = target,
+ transitionSpec = {
+ fadeIn() + scaleInToFitContainer(
+ Alignment.BottomEnd, ContentScale.Inside
+ ) togetherWith
+ fadeOut(tween(100)) using
+ SizeTransform { _, _ ->
+ tween(100, easing = LinearEasing)
+ }
+ }) {
+ if (target) {
+ Box(
+ Modifier
+ .onPlaced {
+ box1Coords = it
+ }
+ .size(200.dp, 400.dp))
+ } else {
+ Box(
+ Modifier
+ .onPlaced { box2Coords = it }
+ .size(100.dp, 50.dp))
+ }
+ }
+ }
+ }
+
+ rule.waitForIdle()
+ rule.mainClock.autoAdvance = false
+ assertEquals(IntSize(200, 400), box1Coords?.size)
+ assertNull(box2Coords)
+
+ rule.runOnIdle {
+ // Start transition from true -> false, size 200,400 -> 100,50
+ target = false
+ }
+ rule.mainClock.advanceTimeByFrame()
+ repeat(10) {
+ rule.mainClock.advanceTimeByFrame()
+ val playTime = 16 * it
+ val bounds = box2Coords?.boundsInRoot()
+ assertNotNull(bounds)
+ val fraction = (playTime / 100f).coerceAtMost(1f)
+ val width = 100f
+ val containerWidth = 200 * (1 - fraction) + 100 * fraction
+ val containerHeight = 400 * (1 - fraction) + 50 * fraction
+ // Since we are testing default behavior, the scaling is based on width.
+ val height = 50f
+ assertEquals(width, bounds!!.width, 0.01f)
+ assertEquals(height, bounds.height, 0.01f)
+ val offset = Alignment.BottomEnd.align(
+ IntSize(width.roundToInt(), height.roundToInt()),
+ IntSize(containerWidth.roundToInt(), containerHeight.roundToInt()),
+ layoutDirection!!
+ )
+ assertEquals(offset, bounds.topLeft.round())
+ }
+ }
+
+ @Test
+ fun testScaleToFitWithFitHeight() {
+ var target by mutableStateOf(true)
+ var box1Coords: LayoutCoordinates? = null
+ var box2Coords: LayoutCoordinates? = null
+ var layoutDirection: LayoutDirection? = null
+ rule.setContent {
+ CompositionLocalProvider(LocalDensity provides Density(1f)) {
+ layoutDirection = LocalLayoutDirection.current
+ AnimatedContent(
+ targetState = target,
+ transitionSpec = {
+ fadeIn() + scaleInToFitContainer(
+ Alignment.Center, ContentScale.FillHeight
+ ) togetherWith fadeOut(tween(100)) using
+ SizeTransform { _, _ ->
+ tween(100, easing = LinearEasing)
+ }
+ }) {
+ if (target) {
+ Box(
+ Modifier
+ .onPlaced {
+ box1Coords = it
+ }
+ .size(200.dp, 400.dp))
+ } else {
+ Box(
+ Modifier
+ .onPlaced { box2Coords = it }
+ .size(100.dp, 250.dp))
+ }
+ }
+ }
+ }
+
+ rule.waitForIdle()
+ rule.mainClock.autoAdvance = false
+ assertEquals(IntSize(200, 400), box1Coords?.size)
+ assertNull(box2Coords)
+
+ rule.runOnIdle {
+ // Start transition from true -> false, size 200,400 -> 100,250
+ target = false
+ }
+ rule.mainClock.advanceTimeByFrame()
+ repeat(10) {
+ rule.mainClock.advanceTimeByFrame()
+ val playTime = 16 * it
+ val bounds = box2Coords?.boundsInRoot()
+ assertNotNull(bounds)
+ val fraction = (playTime / 100f).coerceAtMost(1f)
+ val height = 400 * (1 - fraction) + 250 * fraction
+ val containerWidth = 200 * (1 - fraction) + 100 * fraction
+ // Since we are testing default behavior, the scaling is based on width.
+ val width = height / 250f * 100
+ assertEquals(width, bounds!!.width, 0.01f)
+ assertEquals(height, bounds.height, 0.01f)
+ val offset = Alignment.Center.align(
+ IntSize(width.roundToInt(), height.roundToInt()),
+ IntSize(containerWidth.roundToInt(), height.roundToInt()), layoutDirection!!
+ )
+ assertEquals(offset, bounds.topLeft.round())
+ }
+ }
+
@OptIn(ExperimentalAnimationApi::class)
@Test
fun testExitHoldDefersUntilAllFinished() {
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
index 4449080..da44816 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedContent.kt
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-@file:OptIn(InternalAnimationApi::class)
+@file:OptIn(InternalAnimationApi::class, ExperimentalAnimationApi::class)
package androidx.compose.animation
@@ -38,6 +37,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
@@ -45,14 +45,20 @@
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
+import androidx.compose.ui.graphics.TransformOrigin
+import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.IntrinsicMeasurable
import androidx.compose.ui.layout.IntrinsicMeasureScope
import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.layout.MeasureResult
@@ -60,14 +66,20 @@
import androidx.compose.ui.layout.ParentDataModifier
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.layout
+import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.toSize
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
+import kotlin.math.roundToInt
+import kotlinx.coroutines.CoroutineScope
/**
* [AnimatedContent] is a container that automatically animates its content when [targetState]
@@ -283,9 +295,7 @@
* [AnimatedContentTransitionScope] provides functions that are convenient and only applicable in the
* context of [AnimatedContent], such as [slideIntoContainer] and [slideOutOfContainer].
*/
-
sealed interface AnimatedContentTransitionScope<S> : Transition.Segment<S> {
-
/**
* Customizes the [SizeTransform] of a given [ContentTransform]. For example:
*
@@ -395,13 +405,67 @@
* @sample androidx.compose.animation.samples.SlideIntoContainerSample
*/
val ExitTransition.Companion.Hold: ExitTransition get() = Hold
+
+ /**
+ * This returns the [Alignment] specified on [AnimatedContent].
+ */
+ val contentAlignment: Alignment
+
+ /**
+ * [scaleInToFitContainer] defines an [EnterTransition] that scales the incoming content
+ * based on the (potentially animating) container (i.e. [AnimatedContent]) size. [contentScale]
+ * defines the scaling function. By default, the incoming content will be scaled based on its
+ * width (i.e. [ContentScale.FillWidth]), so that the content fills the container's width.
+ * [alignment] can be used to specify the alignment of the scaled content
+ * within the container of AnimatedContent.
+ *
+ * [scaleInToFitContainer] will measure the content using the final (i.e. lookahead)
+ * constraints, in order to obtain the final layout and apply scaling to that final layout
+ * while the container is resizing.
+ *
+ * @sample androidx.compose.animation.samples.ScaleInToFitContainerSample
+ */
+ @ExperimentalAnimationApi
+ fun scaleInToFitContainer(
+ alignment: Alignment = contentAlignment,
+ contentScale: ContentScale = ContentScale.FillWidth
+ ): EnterTransition
+
+ /**
+ * [scaleOutToFitContainer] defines an [ExitTransition] that scales the outgoing content
+ * based on the (potentially animating) container (i.e. [AnimatedContent]) size.
+ * [contentScale] defines the scaling function. By default, the outgoing content will be scaled
+ * using [ContentScale.FillWidth], so that it fits the container's width.
+ * [alignment] can be used to specify the alignment of the scaled content
+ * within the container of AnimatedContent.
+ *
+ * [scaleOutToFitContainer] will measure the content using the constraints cached
+ * at the beginning of the exit animation so that the content does not get re-laid out during
+ * the exit animation, and instead only scaling will be applied as the container resizes.
+ *
+ * **IMPORTANT**: [scaleOutToFitContainer] does NOT keep the exiting content from being
+ * disposed. Therefore it relies on other ExitTransitions such as [fadeOut] to define a
+ * timeframe for when should be active.
+ *
+ * @sample androidx.compose.animation.samples.ScaleInToFitContainerSample
+ */
+ @ExperimentalAnimationApi
+ fun scaleOutToFitContainer(
+ alignment: Alignment = contentAlignment,
+ contentScale: ContentScale = ContentScale.FillWidth,
+ ): ExitTransition
}
-internal class AnimatedContentTransitionScopeImpl<S> internal constructor(
+internal class AnimatedContentRootScope<S> internal constructor(
internal val transition: Transition<S>,
- internal var contentAlignment: Alignment,
+ lookaheadScope: LookaheadScope,
+ internal val coroutineScope: CoroutineScope,
+ override var contentAlignment: Alignment,
internal var layoutDirection: LayoutDirection
-) : AnimatedContentTransitionScope<S> {
+) : AnimatedContentTransitionScope<S>, LookaheadScope by lookaheadScope {
+ lateinit var rootCoords: LayoutCoordinates
+ lateinit var rootLookaheadCoords: LayoutCoordinates
+
/**
* Initial state of a Transition Segment. This is the state that transition starts from.
*/
@@ -484,7 +548,6 @@
return this == Left || this == Start && layoutDirection == LayoutDirection.Ltr ||
this == End && layoutDirection == LayoutDirection.Rtl
}
-
private val AnimatedContentTransitionScope.SlideDirection.isRight: Boolean
get() {
return this == Right || this == Start && layoutDirection == LayoutDirection.Rtl ||
@@ -532,7 +595,6 @@
}
towards.isRight -> slideOutHorizontally(animationSpec) {
-
val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
targetOffset.invoke(
-calculateOffset(IntSize(it, it), targetSize).x + targetSize.width
@@ -540,7 +602,6 @@
}
towards == Up -> slideOutVertically(animationSpec) {
-
val targetSize = targetSizeMap[transition.targetState]?.value ?: IntSize.Zero
targetOffset.invoke(-calculateOffset(IntSize(it, it), targetSize).y - it)
}
@@ -556,15 +617,45 @@
}
}
+ @ExperimentalAnimationApi
+ override fun scaleInToFitContainer(
+ alignment: Alignment,
+ contentScale: ContentScale
+ ): EnterTransition = EnterTransition(
+ ScaleToFitTransitionKey, ScaleToFitInLookaheadElement(
+ this@AnimatedContentRootScope,
+ contentScale,
+ alignment
+ )
+ )
+
+ @ExperimentalAnimationApi
+ override fun scaleOutToFitContainer(
+ alignment: Alignment,
+ contentScale: ContentScale
+ ): ExitTransition = ExitTransition(
+ ScaleToFitTransitionKey,
+ ScaleToFitInLookaheadElement(
+ this@AnimatedContentRootScope,
+ contentScale,
+ alignment
+ )
+ )
+
internal var measuredSize: IntSize by mutableStateOf(IntSize.Zero)
- internal val targetSizeMap = mutableMapOf<S, State<IntSize>>()
+ internal val targetSizeMap = mutableMapOf<S, MutableState<IntSize>>()
internal var animatedSize: State<IntSize>? = null
// Current size of the container. If there's any size animation, the current size will be
// read from the animation value, otherwise we'll use the current
- private val currentSize: IntSize
+ internal val currentSize: IntSize
get() = animatedSize?.value ?: measuredSize
+ internal val targetSize: IntSize
+ get() = requireNotNull(targetSizeMap[targetState]) {
+ "Error: Target size for AnimatedContent has not been set."
+ }.value
+
@Suppress("ComposableModifierFactory", "ModifierFactoryExtensionFunction")
@Composable
internal fun createSizeAnimationModifier(
@@ -574,17 +665,20 @@
val sizeTransform = rememberUpdatedState(contentTransform.sizeTransform)
if (transition.currentState == transition.targetState) {
shouldAnimateSize = false
- } else {
- // TODO: CurrentSize is only relevant to enter/exit transition, not so much for sizeAnim
- if (sizeTransform.value != null) {
- shouldAnimateSize = true
- }
+ } else if (sizeTransform.value != null) {
+ shouldAnimateSize = true
}
+
return if (shouldAnimateSize) {
- val sizeAnimation = transition.createDeferredAnimation(IntSize.VectorConverter)
+ val sizeAnimation =
+ transition.createDeferredAnimation(IntSize.VectorConverter, "sizeTransform")
remember(sizeAnimation) {
(if (sizeTransform.value?.clip == false) Modifier else Modifier.clipToBounds())
- .then(SizeModifier(sizeAnimation, sizeTransform))
+ .then(
+ SizeModifierInLookaheadElement(
+ this, sizeAnimation, sizeTransform
+ )
+ )
}
} else {
animatedSize = null
@@ -594,42 +688,11 @@
// This helps track the target measurable without affecting the placement order. Target
// measurable needs to be measured first but placed last.
- internal data class ChildData(var isTarget: Boolean) : ParentDataModifier {
+ internal data class ChildData<T>(var targetState: T) : ParentDataModifier {
override fun Density.modifyParentData(parentData: Any?): Any {
return this@ChildData
}
}
-
- private inner class SizeModifier(
- val sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
- val sizeTransform: State<SizeTransform?>,
- ) : LayoutModifierWithPassThroughIntrinsics() {
-
- override fun MeasureScope.measure(
- measurable: Measurable,
- constraints: Constraints
- ): MeasureResult {
-
- val placeable = measurable.measure(constraints)
- val size = sizeAnimation.animate(
- transitionSpec = {
- val initial = targetSizeMap[initialState]?.value ?: IntSize.Zero
- val target = targetSizeMap[targetState]?.value ?: IntSize.Zero
-
- sizeTransform.value?.createAnimationSpec(initial, target) ?: spring()
- }
- ) {
- targetSizeMap[it]?.value ?: IntSize.Zero
- }
- animatedSize = size
- val offset = contentAlignment.align(
- IntSize(placeable.width, placeable.height), size.value, LayoutDirection.Ltr
- )
- return layout(size.value.width, size.value.height) {
- placeable.place(offset)
- }
- }
- }
}
/**
@@ -706,153 +769,269 @@
content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
) {
val layoutDirection = LocalLayoutDirection.current
- val rootScope = remember(this) {
- AnimatedContentTransitionScopeImpl(this, contentAlignment, layoutDirection)
- }
+ val coroutineScope = rememberCoroutineScope()
+ LookaheadScope {
+ val rootScope = remember(this@AnimatedContent) {
+ AnimatedContentRootScope(
+ this@AnimatedContent, this@LookaheadScope,
+ coroutineScope, contentAlignment, layoutDirection
+ )
+ }
+ val currentlyVisible = remember(this) { mutableStateListOf(currentState) }
+ val contentMap = remember(this) { mutableMapOf<S, @Composable() () -> Unit>() }
+ val constraintsMap = remember { mutableMapOf<S, Constraints>() }
- // TODO: remove screen as soon as they are animated out
- val currentlyVisible = remember(this) { mutableStateListOf(currentState) }
- val contentMap = remember(this) { mutableMapOf<S, @Composable() () -> Unit>() }
-
- // This is needed for tooling because it could change currentState directly,
- // as opposed to changing target only. When that happens we need to clear all the
- // visible content and only display the content for the new current state and target state.
- if (!currentlyVisible.contains(currentState)) {
- currentlyVisible.clear()
- currentlyVisible.add(currentState)
- }
-
- if (currentState == targetState) {
- if (currentlyVisible.size != 1 || currentlyVisible[0] != currentState) {
+ // This is needed for tooling because it could change currentState directly,
+ // as opposed to changing target only. When that happens we need to clear all the
+ // visible content and only display the content for the new current state and target state.
+ if (!currentlyVisible.contains(currentState)) {
currentlyVisible.clear()
currentlyVisible.add(currentState)
}
- if (contentMap.size != 1 || contentMap.containsKey(currentState)) {
+
+ if (currentState == targetState) {
+ if (currentlyVisible.size != 1 || currentlyVisible[0] != currentState) {
+ currentlyVisible.clear()
+ currentlyVisible.add(currentState)
+ }
+ if (contentMap.size != 1 || contentMap.containsKey(currentState)) {
+ contentMap.clear()
+ }
+ val targetConstraints = constraintsMap[targetState]
+ constraintsMap.clear()
+ targetConstraints?.let { constraintsMap[targetState] = it }
+ // TODO: Do we want to support changing contentAlignment amid animation?
+ rootScope.contentAlignment = contentAlignment
+ rootScope.layoutDirection = layoutDirection
+ } else if (!currentlyVisible.contains(targetState)) {
+ // Currently visible list always keeps the targetState at the end of the list, unless
+ // it's already in the list in the case of interruption. This makes the composable
+ // associated with the targetState get placed last, so the target composable will be
+ // displayed on top of content associated with other states, unless zIndex is specified.
+ // Replace the target with the same key if any.
+ val id = currentlyVisible.indexOfFirst { contentKey(it) == contentKey(targetState) }
+ if (id == -1) {
+ currentlyVisible.add(targetState)
+ } else {
+ currentlyVisible[id] = targetState
+ }
+ }
+ if (!contentMap.containsKey(targetState) || !contentMap.containsKey(currentState)) {
contentMap.clear()
- }
- // TODO: Do we want to support changing contentAlignment amid animation?
- rootScope.contentAlignment = contentAlignment
- rootScope.layoutDirection = layoutDirection
- }
-
- // Currently visible list always keeps the targetState at the end of the list, unless it's
- // already in the list in the case of interruption. This makes the composable associated with
- // the targetState get placed last, so the target composable will be displayed on top of
- // content associated with other states, unless zIndex is specified.
- if (currentState != targetState && !currentlyVisible.contains(targetState)) {
- // Replace the target with the same key if any
- val id = currentlyVisible.indexOfFirst { contentKey(it) == contentKey(targetState) }
- if (id == -1) {
- currentlyVisible.add(targetState)
- } else {
- currentlyVisible[id] = targetState
- }
- }
-
- if (!contentMap.containsKey(targetState) || !contentMap.containsKey(currentState)) {
- contentMap.clear()
- currentlyVisible.fastForEach { stateForContent ->
- contentMap[stateForContent] = {
- val specOnEnter = remember { transitionSpec(rootScope) }
- // NOTE: enter and exit for this AnimatedVisibility will be using different spec,
- // naturally.
- val exit =
- remember(segment.targetState == stateForContent) {
- if (segment.targetState == stateForContent) {
- ExitTransition.None
- } else {
- rootScope.transitionSpec().initialContentExit
- }
- }
- val childData = remember {
- AnimatedContentTransitionScopeImpl.ChildData(stateForContent == targetState)
+ val enter = transitionSpec(rootScope).targetContentEnter
+ val exit = rootScope.transitionSpec().initialContentExit
+ val zIndex = transitionSpec(rootScope).targetContentZIndex
+ currentlyVisible.fastForEach { stateForContent ->
+ contentMap[stateForContent] = {
+ PopulateContentFor(
+ stateForContent, rootScope, enter, exit, zIndex, currentlyVisible, content
+ )
}
- // TODO: Will need a custom impl of this to: 1) get the signal for when
- // the animation is finished, 2) get the target size properly
- AnimatedEnterExitImpl(
- this,
- { it == stateForContent },
- enter = specOnEnter.targetContentEnter,
- exit = exit,
- modifier = Modifier
- .layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
- layout(placeable.width, placeable.height) {
- placeable.place(0, 0, zIndex = specOnEnter.targetContentZIndex)
+ }
+ }
+ val contentTransform = remember(rootScope, segment) { transitionSpec(rootScope) }
+ val sizeModifier = rootScope.createSizeAnimationModifier(contentTransform)
+ Layout(
+ modifier = modifier
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ coordinates?.let {
+ if (isLookingAhead) {
+ rootScope.rootLookaheadCoords = it
+ } else {
+ rootScope.rootCoords = it
}
}
- .then(childData.apply { isTarget = stateForContent == targetState }),
- shouldDisposeBlock = { currentState, targetState ->
- currentState == EnterExitState.PostExit &&
- targetState == EnterExitState.PostExit &&
- !exit.data.hold
- }
- ) {
- // TODO: Should Transition.AnimatedVisibility have an end listener?
- DisposableEffect(this) {
- onDispose {
- currentlyVisible.remove(stateForContent)
- rootScope.targetSizeMap.remove(stateForContent)
- }
- }
- rootScope.targetSizeMap[stateForContent] =
- (this as AnimatedVisibilityScopeImpl).targetSize
- with(remember { AnimatedContentScopeImpl(this) }) {
- content(stateForContent)
+ placeable.place(0, 0)
}
}
+ .then(sizeModifier),
+ content = {
+ currentlyVisible.forEach {
+ key(contentKey(it)) { contentMap[it]?.invoke() }
+ }
+ },
+ measurePolicy = remember {
+ AnimatedContentMeasurePolicy(
+ rootScope, constraintsMap
+ )
}
- }
+ )
}
-
- val contentTransform = remember(rootScope, segment) { transitionSpec(rootScope) }
- val sizeModifier = rootScope.createSizeAnimationModifier(contentTransform)
- Layout(
- modifier = modifier.then(sizeModifier),
- content = {
- currentlyVisible.forEach {
- key(contentKey(it)) {
- contentMap[it]?.invoke()
- }
- }
- },
- measurePolicy = remember { AnimatedContentMeasurePolicy(rootScope) }
- )
}
-private class AnimatedContentMeasurePolicy(val rootScope: AnimatedContentTransitionScopeImpl<*>) :
- MeasurePolicy {
+/**
+ * Creates content for a specific state based on the current Transition, enter/exit and the content
+ * lookup lambda.
+ */
+@Composable
+private inline fun <S> Transition<S>.PopulateContentFor(
+ stateForContent: S,
+ rootScope: AnimatedContentRootScope<S>,
+ enter: EnterTransition,
+ exit: ExitTransition,
+ zIndex: Float,
+ currentlyVisible: SnapshotStateList<S>,
+ crossinline content: @Composable() AnimatedContentScope.(targetState: S) -> Unit
+) {
+ var activeEnter by remember { mutableStateOf(enter) }
+ var activeExit by remember { mutableStateOf(ExitTransition.None) }
+ val targetZIndex = remember { zIndex }
+
+ val isEntering = targetState == stateForContent
+ if (targetState == currentState) {
+ // Transition finished, reset active enter & exit.
+ activeEnter = androidx.compose.animation.EnterTransition.None
+ activeExit = androidx.compose.animation.ExitTransition.None
+ } else if (isEntering) {
+ // If the previous enter transition never finishes when multiple
+ // interruptions happen, avoid adding new enter transitions for simplicity.
+ if (activeEnter == androidx.compose.animation.EnterTransition.None)
+ activeEnter += enter
+ } else {
+ // If the previous exit transition never finishes when multiple
+ // interruptions happen, avoid adding new enter transitions for simplicity.
+ if (activeExit == androidx.compose.animation.ExitTransition.None) {
+ activeExit += exit
+ }
+ }
+ val childData = remember { AnimatedContentRootScope.ChildData(stateForContent) }
+ AnimatedEnterExitImpl(
+ this,
+ { it == stateForContent },
+ enter = activeEnter,
+ exit = activeExit,
+ modifier = Modifier
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.place(0, 0, zIndex = targetZIndex)
+ }
+ }
+ .then(childData)
+ .then(
+ if (isEntering) {
+ activeEnter[ScaleToFitTransitionKey]
+ ?: activeExit[ScaleToFitTransitionKey] ?: androidx.compose.ui.Modifier
+ } else {
+ activeExit[ScaleToFitTransitionKey]
+ ?: activeEnter[ScaleToFitTransitionKey] ?: androidx.compose.ui.Modifier
+ }
+ ),
+ shouldDisposeBlock = { currentState, targetState ->
+ currentState == androidx.compose.animation.EnterExitState.PostExit &&
+ targetState == androidx.compose.animation.EnterExitState.PostExit &&
+ !activeExit.data.hold
+ },
+ onLookaheadMeasured = {
+ if (isEntering) rootScope.targetSizeMap.getOrPut(targetState) {
+ mutableStateOf(it)
+ }.value = it
+ }
+ ) {
+ // TODO: Should Transition.AnimatedVisibility have an end listener?
+ DisposableEffect(this) {
+ onDispose {
+ currentlyVisible.remove(stateForContent)
+ rootScope.targetSizeMap.remove(stateForContent)
+ }
+ }
+ with(remember { AnimatedContentScopeImpl(this) }) {
+ content(stateForContent)
+ }
+ }
+}
+
+/**
+ * This measure policy returns the target content size in the lookahead pass, and the max width
+ * and height needed for all contents to fit during the main measure pass.
+ *
+ * The measure policy will measure all children with lookahead constraints. For outgoing content,
+ * we will use the constraints recorded before the content started to exit. This enables the
+ * outgoing content to not change constraints on its way out.
+ */
+@Suppress("UNCHECKED_CAST")
+private class AnimatedContentMeasurePolicy<S>(
+ val rootScope: AnimatedContentRootScope<S>,
+ val constraintsMap: MutableMap<S, Constraints>
+) : MeasurePolicy {
override fun MeasureScope.measure(
measurables: List<Measurable>,
constraints: Constraints
): MeasureResult {
val placeables = arrayOfNulls<Placeable>(measurables.size)
// Measure the target composable first (but place it on top unless zIndex is specified)
+ val targetState = rootScope.targetState
measurables.fastForEachIndexed { index, measurable ->
- if ((measurable.parentData as? AnimatedContentTransitionScopeImpl.ChildData)
- ?.isTarget == true
+ if ((measurable.parentData as? AnimatedContentRootScope.ChildData<*>)
+ ?.targetState == targetState
) {
- placeables[index] = measurable.measure(constraints)
+ // Record lookahead constraints and always use it to measure target content.
+ val lookaheadConstraints = if (isLookingAhead) {
+ constraintsMap[targetState] = constraints
+ constraints
+ } else {
+ requireNotNull(constraintsMap[targetState]) {
+ "Lookahead pass was never done for target content."
+ }
+ }
+ placeables[index] = measurable.measure(lookaheadConstraints)
}
}
+ // If no content is defined for target state, set the target size to zero
+ rootScope.targetSizeMap.getOrPut(targetState) { mutableStateOf(IntSize.Zero) }
+
+ val initialState = rootScope.initialState
// Measure the non-target composables after target, since these have no impact on
// container size in the size animation.
measurables.fastForEachIndexed { index, measurable ->
+ val stateForContent =
+ (measurable.parentData as? AnimatedContentRootScope.ChildData<*>)
+ ?.targetState
if (placeables[index] == null) {
- placeables[index] = measurable.measure(constraints)
+ val lookaheadConstraints =
+ constraintsMap[stateForContent] ?: if (isLookingAhead) {
+ constraintsMap[stateForContent as S] = constraints
+ constraints
+ } else {
+ requireNotNull(constraintsMap[stateForContent as S]) {
+ "Error: Lookahead pass never happened for state: $stateForContent"
+ }
+ }
+ placeables[index] = measurable.measure(lookaheadConstraints).also {
+ // If the initial state size isn't in the map, add it. This could be possible
+ // when the initial state is specified to be different than target state upon
+ // entering composition.
+ if (stateForContent == initialState &&
+ isLookingAhead &&
+ !rootScope.targetSizeMap.containsKey(initialState)
+ ) {
+ rootScope.targetSizeMap[initialState] =
+ mutableStateOf(IntSize(it.width, it.height))
+ }
+ }
}
}
-
- val maxWidth: Int = placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
- val maxHeight = placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
- rootScope.measuredSize = IntSize(maxWidth, maxHeight)
+ val lookaheadSize = rootScope.targetSizeMap[targetState]!!.value
+ val measuredWidth = if (isLookingAhead) {
+ lookaheadSize.width
+ } else {
+ placeables.maxByOrNull { it?.width ?: 0 }?.width ?: 0
+ }
+ val measuredHeight = if (isLookingAhead) {
+ lookaheadSize.height
+ } else {
+ placeables.maxByOrNull { it?.height ?: 0 }?.height ?: 0
+ }
+ rootScope.measuredSize = IntSize(measuredWidth, measuredHeight)
// Position the children.
- return layout(maxWidth, maxHeight) {
+ return layout(measuredWidth, measuredHeight) {
placeables.forEach { placeable ->
placeable?.let {
val offset = rootScope.contentAlignment.align(
IntSize(it.width, it.height),
- IntSize(maxWidth, maxHeight),
+ IntSize(measuredWidth, measuredHeight),
LayoutDirection.Ltr
)
it.place(offset.x, offset.y)
@@ -881,3 +1060,154 @@
width: Int
) = measurables.asSequence().map { it.maxIntrinsicHeight(width) }.maxOrNull() ?: 0
}
+
+private class SizeModifierInLookaheadNode<S>(
+ var rootScope: AnimatedContentRootScope<S>,
+ var sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
+ var sizeTransform: State<SizeTransform?>,
+) : LayoutModifierNodeWithPassThroughIntrinsics() {
+
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints,
+ ): MeasureResult {
+ val placeable = measurable.measure(constraints)
+ val size = if (isLookingAhead) {
+ val targetSize = IntSize(placeable.width, placeable.height)
+ // lookahead pass
+ rootScope.animatedSize = sizeAnimation.animate(
+ transitionSpec = {
+ val initial = rootScope.targetSizeMap[initialState]?.value ?: IntSize.Zero
+ val target = rootScope.targetSizeMap[targetState]?.value ?: IntSize.Zero
+ sizeTransform.value?.createAnimationSpec(initial, target) ?: spring()
+ }
+ ) {
+ rootScope.targetSizeMap[it]?.value ?: IntSize.Zero
+ }
+ targetSize
+ } else {
+ rootScope.animatedSize!!.value
+ }
+ val offset = rootScope.contentAlignment.align(
+ IntSize(placeable.width, placeable.height), size, LayoutDirection.Ltr
+ )
+ return layout(size.width, size.height) {
+ placeable.place(offset)
+ }
+ }
+}
+
+private data class SizeModifierInLookaheadElement<S>(
+ val rootScope: AnimatedContentRootScope<S>,
+ val sizeAnimation: Transition<S>.DeferredAnimation<IntSize, AnimationVector2D>,
+ val sizeTransform: State<SizeTransform?>,
+) : ModifierNodeElement<SizeModifierInLookaheadNode<S>>() {
+ override fun create(): SizeModifierInLookaheadNode<S> {
+ return SizeModifierInLookaheadNode(rootScope, sizeAnimation, sizeTransform)
+ }
+
+ override fun update(node: SizeModifierInLookaheadNode<S>) {
+ node.rootScope = rootScope
+ node.sizeTransform = sizeTransform
+ node.sizeAnimation = sizeAnimation
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "sizeTransform"
+ properties["sizeTransform"] = sizeTransform
+ properties["sizeAnimation"] = sizeAnimation
+ }
+}
+
+private data class ScaleToFitInLookaheadElement(
+ val rootScope: AnimatedContentRootScope<*>,
+ val contentScale: ContentScale,
+ val alignment: Alignment
+) : ModifierNodeElement<ScaleToFitInLookaheadNode>() {
+ override fun create(): ScaleToFitInLookaheadNode =
+ ScaleToFitInLookaheadNode(rootScope, contentScale, alignment)
+
+ override fun update(node: ScaleToFitInLookaheadNode) {
+ node.rootScope = rootScope
+ node.contentScale = contentScale
+ node.alignment = alignment
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "scaleToFit"
+ properties["rootScope"] = rootScope
+ properties["scale"] = contentScale
+ properties["alignment"] = alignment
+ }
+}
+
+/**
+ * Creates a Modifier Node to: 1) measure the layout with lookahead constraints, 2) scale the
+ * resulting (potentially unfitting) layout based on the resizing container using the given
+ * [contentScale] lambda.
+ *
+ * This node is designed to work in a lookahead scope, therefore it anticipates lookahead pass
+ * before actual measure pass.
+ */
+private class ScaleToFitInLookaheadNode(
+ var rootScope: AnimatedContentRootScope<*>,
+ var contentScale: ContentScale,
+ var alignment: Alignment
+) : Modifier.Node(), LayoutModifierNode {
+ private var lookaheadConstraints: Constraints = Constraints()
+ set(value) {
+ lookaheadPassOccurred = true
+ field = value
+ }
+ get() {
+ require(lookaheadPassOccurred) {
+ "Error: Attempting to read lookahead constraints before lookahead pass."
+ }
+ return field
+ }
+ private var lookaheadPassOccurred = false
+
+ override fun onDetach() {
+ super.onDetach()
+ lookaheadPassOccurred = false
+ }
+
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ if (isLookingAhead) lookaheadConstraints = constraints
+ // Measure with lookahead constraints.
+ val placeable = measurable.measure(lookaheadConstraints)
+ val contentSize = IntSize(placeable.width, placeable.height)
+ val sizeToReport = if (isLookingAhead) {
+ // report size of the target content, as that's what the content will be scaled to.
+ rootScope.targetSize
+ } else {
+ // report current animated size && scale based on that and full size
+ rootScope.currentSize
+ }
+ val resolvedScale =
+ contentScale.computeScaleFactor(contentSize.toSize(), sizeToReport.toSize())
+ return layout(sizeToReport.width, sizeToReport.height) {
+ val (x, y) = alignment.align(
+ IntSize(
+ (contentSize.width * resolvedScale.scaleX).roundToInt(),
+ (contentSize.height * resolvedScale.scaleY).roundToInt()
+ ),
+ sizeToReport,
+ layoutDirection
+ )
+ placeable.placeWithLayer(x, y) {
+ scaleX = resolvedScale.scaleX
+ scaleY = resolvedScale.scaleY
+ transformOrigin = TransformOrigin(0f, 0f)
+ }
+ }
+ }
+}
+
+/**
+ * Fixed key to read customization out of EnterTransition and ExitTransition.
+ */
+private val ScaleToFitTransitionKey = Any()
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
index 7e03d6f..367c85b 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimatedVisibility.kt
@@ -49,6 +49,7 @@
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
+import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
@@ -129,7 +130,7 @@
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visible, label)
- AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+ AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
}
/**
@@ -204,7 +205,7 @@
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visible, label)
- AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+ AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
}
/**
@@ -277,7 +278,7 @@
content: @Composable AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visible, label)
- AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+ AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
}
/**
@@ -383,7 +384,7 @@
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visibleState, label)
- AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+ AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
}
/**
@@ -458,7 +459,7 @@
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visibleState, label)
- AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+ AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
}
/**
@@ -534,7 +535,7 @@
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
val transition = updateTransition(visibleState, label)
- AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content = content)
+ AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
}
/**
@@ -607,7 +608,7 @@
enter: EnterTransition = fadeIn() + expandIn(),
exit: ExitTransition = shrinkOut() + fadeOut(),
content: @Composable() AnimatedVisibilityScope.() -> Unit
-) = AnimatedEnterExitImpl(this, visible, modifier, enter, exit, content = content)
+) = AnimatedVisibilityImpl(this, visible, modifier, enter, exit, content = content)
/**
* This is the scope for the content of [AnimatedVisibility]. In this scope, direct and
@@ -719,8 +720,51 @@
content()
}
-// RowScope and ColumnScope AnimatedEnterExit extensions and AnimatedEnterExit without a receiver
-// converge here.
+/**
+ * RowScope and ColumnScope AnimatedVisibility extensions and AnimatedVisibility without a receiver
+ * converge here.
+ * AnimatedVisibilityImpl sets up 2 things: 1) It adds a modifier to report 0 size in lookahead
+ * when animating out. 2) It sets up a criteria for when content should be disposed.
+ */
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+internal fun <T> AnimatedVisibilityImpl(
+ transition: Transition<T>,
+ visible: (T) -> Boolean,
+ modifier: Modifier,
+ enter: EnterTransition,
+ exit: ExitTransition,
+ content: @Composable() AnimatedVisibilityScope.() -> Unit
+) {
+ AnimatedEnterExitImpl(
+ transition = transition,
+ visible = visible,
+ modifier = modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ val (w, h) =
+ if (isLookingAhead && !visible(transition.targetState)) {
+ IntSize.Zero
+ } else {
+ IntSize(placeable.width, placeable.height)
+ }
+ layout(w, h) {
+ placeable.place(0, 0)
+ }
+ },
+ enter = enter,
+ exit = exit,
+ shouldDisposeBlock = { current, target -> current == target && target == PostExit },
+ content = content
+ )
+}
+
+/**
+ * Observes lookahead size.
+ */
+internal fun interface OnLookaheadMeasured {
+ fun invoke(size: IntSize)
+}
+
@OptIn(
ExperimentalTransitionApi::class,
InternalAnimationApi::class,
@@ -733,9 +777,8 @@
modifier: Modifier,
enter: EnterTransition,
exit: ExitTransition,
- shouldDisposeBlock: (EnterExitState, EnterExitState) -> Boolean = { current, target ->
- current == target && target == PostExit
- },
+ shouldDisposeBlock: (EnterExitState, EnterExitState) -> Boolean,
+ onLookaheadMeasured: OnLookaheadMeasured? = null,
content: @Composable() AnimatedVisibilityScope.() -> Unit
) {
if (visible(transition.targetState) || visible(transition.currentState) ||
@@ -771,7 +814,21 @@
val scope = remember(transition) { AnimatedVisibilityScopeImpl(childTransition) }
Layout(
content = { scope.content() },
- modifier = modifier.then(childTransition.createModifier(enter, exit, "Built-in")),
+ modifier = modifier
+ .then(childTransition.createModifier(enter, exit, "Built-in")
+ .then(if (onLookaheadMeasured != null) {
+ Modifier.layout { measurable, constraints ->
+ measurable.measure(constraints).run {
+ if (isLookingAhead) {
+ onLookaheadMeasured.invoke(IntSize(width, height))
+ }
+ layout(width, height) {
+ place(0, 0)
+ }
+ }
+ }
+ } else Modifier)
+ ),
measurePolicy = remember { AnimatedEnterExitMeasurePolicy(scope) }
)
}
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
index e9d8ea9..f5a9d27 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
@@ -113,7 +113,8 @@
fade = data.fade ?: enter.data.fade,
slide = data.slide ?: enter.data.slide,
changeSize = data.changeSize ?: enter.data.changeSize,
- scale = data.scale ?: enter.data.scale
+ scale = data.scale ?: enter.data.scale,
+ effectsMap = data.effectsMap + enter.data.effectsMap
)
)
}
@@ -198,7 +199,8 @@
slide = data.slide ?: exit.data.slide,
changeSize = data.changeSize ?: exit.data.changeSize,
scale = data.scale ?: exit.data.scale,
- hold = data.hold || exit.data.hold
+ hold = data.hold || exit.data.hold,
+ effectsMap = data.effectsMap + exit.data.effectsMap
)
)
}
@@ -796,6 +798,18 @@
val animationSpec: FiniteAnimationSpec<Float>
)
+internal fun EnterTransition(
+ key: Any,
+ node: ModifierNodeElement<out Modifier.Node>
+): EnterTransition =
+ EnterTransitionImpl(TransitionData(effectsMap = mapOf(key to node)))
+
+internal fun ExitTransition(
+ key: Any,
+ node: ModifierNodeElement<out Modifier.Node>
+): ExitTransition =
+ ExitTransitionImpl(TransitionData(effectsMap = mapOf(key to node)))
+
@Immutable
private class EnterTransitionImpl(override val data: TransitionData) : EnterTransition()
@@ -822,9 +836,18 @@
val slide: Slide? = null,
val changeSize: ChangeSize? = null,
val scale: Scale? = null,
- val hold: Boolean = false
+ val hold: Boolean = false,
+ val effectsMap: Map<Any, ModifierNodeElement<out Modifier.Node>> = emptyMap()
)
+@Suppress("ModifierFactoryExtensionFunction", "ModifierFactoryReturnType")
+internal operator fun EnterTransition.get(key: Any): ModifierNodeElement<out Modifier.Node>? =
+ data.effectsMap[key]
+
+@Suppress("ModifierFactoryExtensionFunction", "ModifierFactoryReturnType")
+internal operator fun ExitTransition.get(key: Any): ModifierNodeElement<out Modifier.Node>? =
+ data.effectsMap[key]
+
@OptIn(ExperimentalAnimationApi::class, InternalAnimationApi::class)
@Suppress("ModifierFactoryExtensionFunction", "ComposableModifierFactory")
@Composable
@@ -833,7 +856,6 @@
exit: ExitTransition,
label: String
): Modifier {
-
// Active enter & active exit reference the enter and exit transition that is currently being
// used. It is important to preserve the active enter/exit that was previously used before
// changing target state, such that if the previous enter/exit is interrupted, we still hold
@@ -879,7 +901,6 @@
activeExit.data.changeSize?.clip == false) || !shouldAnimateSizeChange
val graphicsLayerBlock = createGraphicsLayerBlock(activeEnter, activeExit, label)
-
return Modifier
.graphicsLayer(clip = !disableClip)
.then(
@@ -1026,9 +1047,6 @@
}
}
- private fun targetConstraints(default: Constraints) =
- if (lookaheadConstraintsAvailable) lookaheadConstraints else default
-
val sizeTransitionSpec: Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<IntSize> =
{
when {
@@ -1097,15 +1115,15 @@
val measuredSize = IntSize(placeable.width, placeable.height)
lookaheadSize = measuredSize
lookaheadConstraints = constraints
- val sizeToReport = if (transition.targetState == EnterExitState.Visible)
- measuredSize
- else
- IntSize.Zero
- return layout(sizeToReport.width, sizeToReport.height) {
+ return layout(measuredSize.width, measuredSize.height) {
placeable.place(0, 0)
}
} else {
- val placeable = measurable.measure(targetConstraints(constraints))
+ // Measure the content based on the current constraints passed down from parent.
+ // AnimatedContent will measure outgoing children with a cached constraints to avoid
+ // re-layout the outgoing content. At the animateEnterExit() level, it's not best not
+ // to make assumptions, which is why we use constraints from parent.
+ val placeable = measurable.measure(constraints)
val measuredSize = IntSize(placeable.width, placeable.height)
val target = if (lookaheadSize.isValid) lookaheadSize else measuredSize
val animSize = sizeAnimation?.animate(sizeTransitionSpec) { sizeByState(it, target) }
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
index f100c5d..e1af9da 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
@@ -4117,4 +4117,38 @@
}
"""
)
+
+ @Test
+ fun test_ComposableLambdaWithUnusedParameter() = verifyComposeIrTransform(
+ source = """
+ import androidx.compose.runtime.*
+
+ val layoutLambda = @Composable { _: Int ->
+ Layout()
+ }
+ """,
+ extra = """
+ import androidx.compose.runtime.*
+
+ @Composable inline fun Layout() {}
+ """,
+ expectedTransformed = """
+ val layoutLambda: Function3<Int, Composer, Int, Unit> = ComposableSingletons%TestKt.lambda-1
+ internal object ComposableSingletons%TestKt {
+ val lambda-1: Function3<Int, Composer, Int, Unit> = composableLambdaInstance(<>, false) { <unused var>: Int, %composer: Composer?, %changed: Int ->
+ if (%changed and 0b01010001 !== 0b00010000 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ Layout(%composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ }
+ }
+ """
+ )
}
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
index 606cc70..98786eb 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionalInterfaceTransformTests.kt
@@ -387,4 +387,88 @@
}
"""
)
+
+ @Test
+ fun testComposableFunInterfaceWAnonymousParam() = verifyComposeIrTransform(
+ """
+ import androidx.compose.runtime.*
+
+ fun interface Consumer {
+ @Composable operator fun invoke(t: Int)
+ }
+
+ @Composable fun Test(int: Int) {
+ Example { _ ->
+ }
+ }
+
+ @Composable fun Example(consumer: Consumer) {
+ }
+ """,
+ """
+ interface Consumer {
+ @Composable
+ abstract fun invoke(t: Int, %composer: Composer?, %changed: Int)
+ }
+ @Composable
+ fun Test(int: Int, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(Test)<Exampl...>:Test.kt")
+ if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ Example(class <no name provided> : Consumer {
+ @Composable
+ override fun invoke(<unused var>: Int, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(invoke):Test.kt")
+ if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ Unit
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ val tmp0_rcvr = <this>
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ tmp0_rcvr.invoke(<unused var>, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+ }
+ }
+ <no name provided>(), %composer, 0)
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ Test(int, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+ }
+ @Composable
+ fun Example(consumer: Consumer, %composer: Composer?, %changed: Int) {
+ %composer = %composer.startRestartGroup(<>)
+ sourceInformation(%composer, "C(Example):Test.kt")
+ if (%changed and 0b0001 !== 0 || !%composer.skipping) {
+ if (isTraceInProgress()) {
+ traceEventStart(<>, %changed, -1, <>)
+ }
+ if (isTraceInProgress()) {
+ traceEventEnd()
+ }
+ } else {
+ %composer.skipToGroupEnd()
+ }
+ %composer.endRestartGroup()?.updateScope { %composer: Composer?, %force: Int ->
+ Example(consumer, %composer, updateChangedFlags(%changed or 0b0001))
+ }
+ }
+ """
+ )
}
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index e334859..07c13e3 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -1689,12 +1689,20 @@
)
if (defaultParam == null) {
- require(parameterCount == defaultIndex) // param count is 1-based, index is 0-based
+ // param count is 1-based, index is 0-based
+ require(parameterCount == defaultIndex) {
+ "Expected $defaultIndex params for ${function.fqNameWhenAvailable}, " +
+ "found $parameterCount"
+ }
} else {
+ val expectedParamCount = defaultIndex +
+ defaultParamCount(contextParameterCount + numRealValueParameters)
require(
- parameterCount == defaultIndex +
- defaultParamCount(contextParameterCount + numRealValueParameters)
- )
+ parameterCount == expectedParamCount
+ ) {
+ "Expected $expectedParamCount params for ${function.fqNameWhenAvailable}, " +
+ "found $parameterCount"
+ }
}
val lambda = irLambdaExpression(
@@ -3875,7 +3883,6 @@
paramName.startsWith(KtxNameConventions.CHANGED_PARAMETER.identifier) ->
changedParams += param
paramName.startsWith("\$context_receiver_") ||
- paramName.startsWith("\$anonymous\$parameter") ||
paramName.startsWith("\$name\$for\$destructuring") ||
paramName.startsWith("\$noName_") ||
paramName == "\$this" -> Unit
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
index 04c7f2c..841ab83a 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
@@ -1572,7 +1572,8 @@
get() = when {
// FIR generates both <iterator> and tmp0_for_iterator...
origin == IrDeclarationOrigin.FOR_LOOP_ITERATOR -> "<iterator>"
- !useFir && origin == IrDeclarationOrigin.UNDERSCORE_PARAMETER -> "<unused var>"
+ // $anonymous$parameter$x vs $unused$var$x
+ origin == IrDeclarationOrigin.UNDERSCORE_PARAMETER -> "<unused var>"
!useFir && name.asString().endsWith("_elvis_lhs") -> "<elvis>"
!useFir && name.asString() == "\$this\$null" -> "<this>"
else -> name.asString()
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/InputsTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/InputsTest.kt
index 80e5b39..cc3dfdf 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/InputsTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/InputsTest.kt
@@ -24,6 +24,7 @@
import androidx.compose.ui.test.assertRangeInfoEquals
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
+import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,6 +38,7 @@
val rule = createComposeRule()
@Test
+ @Ignore("b/293410369")
fun sliderPosition_valueCoercion() {
val state = mutableStateOf(0f)
rule.setContent {
diff --git a/compose/foundation/foundation/api/current.ignore b/compose/foundation/foundation/api/current.ignore
new file mode 100644
index 0000000..2e4834c
--- /dev/null
+++ b/compose/foundation/foundation/api/current.ignore
@@ -0,0 +1,5 @@
+// Baseline format: 1.0
+RemovedMethod: androidx.compose.foundation.text.KeyboardOptions#KeyboardOptions(int, boolean, int, int):
+ Removed constructor androidx.compose.foundation.text.KeyboardOptions(int,boolean,int,int)
+RemovedMethod: androidx.compose.foundation.text.KeyboardOptions#copy(int, boolean, int, int):
+ Removed method androidx.compose.foundation.text.KeyboardOptions.copy(int,boolean,int,int)
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 469ab3a..478059f 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -881,7 +881,8 @@
}
public final class LazyLayoutKt {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+ method @Deprecated @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+ method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(kotlin.jvm.functions.Function0<? extends androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider> itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
}
@SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public sealed interface LazyLayoutMeasureScope extends androidx.compose.ui.layout.MeasureScope {
@@ -1380,16 +1381,20 @@
}
@androidx.compose.runtime.Immutable public final class KeyboardOptions {
- ctor public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
- method public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor @Deprecated public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+ method @Deprecated public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ method public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
method public boolean getAutoCorrect();
method public int getCapitalization();
method public int getImeAction();
method public int getKeyboardType();
+ method public androidx.compose.ui.text.input.PlatformImeOptions? getPlatformImeOptions();
property public final boolean autoCorrect;
property public final int capitalization;
property public final int imeAction;
property public final int keyboardType;
+ property public final androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions;
field public static final androidx.compose.foundation.text.KeyboardOptions.Companion Companion;
}
diff --git a/compose/foundation/foundation/api/restricted_current.ignore b/compose/foundation/foundation/api/restricted_current.ignore
new file mode 100644
index 0000000..2e4834c
--- /dev/null
+++ b/compose/foundation/foundation/api/restricted_current.ignore
@@ -0,0 +1,5 @@
+// Baseline format: 1.0
+RemovedMethod: androidx.compose.foundation.text.KeyboardOptions#KeyboardOptions(int, boolean, int, int):
+ Removed constructor androidx.compose.foundation.text.KeyboardOptions(int,boolean,int,int)
+RemovedMethod: androidx.compose.foundation.text.KeyboardOptions#copy(int, boolean, int, int):
+ Removed method androidx.compose.foundation.text.KeyboardOptions.copy(int,boolean,int,int)
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index a6d9ed6..a608e1e 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -883,7 +883,8 @@
}
public final class LazyLayoutKt {
- method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+ method @Deprecated @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
+ method @SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Composable public static void LazyLayout(kotlin.jvm.functions.Function0<? extends androidx.compose.foundation.lazy.layout.LazyLayoutItemProvider> itemProvider, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.lazy.layout.LazyLayoutPrefetchState? prefetchState, kotlin.jvm.functions.Function2<? super androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measurePolicy);
}
@SuppressCompatibility @androidx.compose.foundation.ExperimentalFoundationApi @androidx.compose.runtime.Stable public sealed interface LazyLayoutMeasureScope extends androidx.compose.ui.layout.MeasureScope {
@@ -1382,16 +1383,20 @@
}
@androidx.compose.runtime.Immutable public final class KeyboardOptions {
- ctor public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
- method public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor @Deprecated public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor public KeyboardOptions(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+ method @Deprecated public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ method public androidx.compose.foundation.text.KeyboardOptions copy(optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
method public boolean getAutoCorrect();
method public int getCapitalization();
method public int getImeAction();
method public int getKeyboardType();
+ method public androidx.compose.ui.text.input.PlatformImeOptions? getPlatformImeOptions();
property public final boolean autoCorrect;
property public final int capitalization;
property public final int imeAction;
property public final int keyboardType;
+ property public final androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions;
field public static final androidx.compose.foundation.text.KeyboardOptions.Companion Companion;
}
diff --git a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt
index 2e190b3..bda7bb1 100644
--- a/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt
+++ b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/lazy/LazyGridScrollingBenchmark.kt
@@ -22,9 +22,11 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
@@ -184,7 +186,7 @@
LazyHorizontalGrid(
rows = GridCells.Fixed(2),
state = state,
- modifier = Modifier.requiredHeight(400.dp).fillMaxWidth(),
+ modifier = Modifier.requiredWidth(400.dp).fillMaxHeight(),
flingBehavior = NoFlingBehavior
) {
items(2) {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt
index 6294141..b756f09 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/gesture/snapping/LazyGridSnapFlingBehaviorTest.kt
@@ -61,6 +61,7 @@
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlinx.coroutines.runBlocking
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
@@ -178,6 +179,7 @@
}
}
+ @Ignore // b/293513475
@Test
fun aboveThresholdVelocityBackward_notLargeEnoughScroll_shouldGoToPreviousPage() {
var lazyGridState: LazyGridState? = null
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
index d05d1f1..eab253b 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutStateRestorationTest.kt
@@ -299,20 +299,19 @@
indexToKey: (Int) -> Any = { getDefaultLazyLayoutKey(it) },
content: @Composable (Int) -> Unit
) {
- LazyLayout(
- itemProvider = remember(itemCount, indexToKey, content as Any) {
- object : LazyLayoutItemProvider {
- override val itemCount: Int = itemCount()
+ val provider = remember(itemCount, indexToKey, content as Any) {
+ object : LazyLayoutItemProvider {
+ override val itemCount: Int = itemCount()
- @Composable
- override fun Item(index: Int, key: Any) {
- content(index)
- }
-
- override fun getKey(index: Int) = indexToKey(index)
+ @Composable
+ override fun Item(index: Int, key: Any) {
+ content(index)
}
+
+ override fun getKey(index: Int) = indexToKey(index)
}
- ) { constraints ->
+ }
+ LazyLayout(itemProvider = { provider }) { constraints ->
val placeables = mutableListOf<Placeable>()
repeat(itemCount()) { index ->
if (itemIsVisible(index)) {
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt
index 7cedc56..cd762bf 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutTest.kt
@@ -163,7 +163,7 @@
LazyLayout(itemProvider) {
val constraints = Constraints.fixed(100, 100)
val items = mutableListOf<Placeable>()
- repeat(itemProvider.itemCount) { index ->
+ repeat(itemProvider().itemCount) { index ->
items.addAll(measure(index, constraints))
}
layout(100, 100) {
@@ -204,7 +204,7 @@
LazyLayout(itemProvider) {
val constraints = Constraints.fixed(100, 100)
val items = mutableListOf<Placeable>()
- repeat(itemProvider.itemCount) { index ->
+ repeat(itemProvider().itemCount) { index ->
items.addAll(measure(index, constraints))
}
layout(100, 100) {
@@ -463,7 +463,7 @@
override fun getKey(index: Int) = stateList[index]
}
rule.setContent {
- LazyLayout(itemProvider) { constraint ->
+ LazyLayout({ itemProvider }) { constraint ->
measure(0, constraint)
layout(100, 100) {}
}
@@ -483,8 +483,8 @@
private fun itemProvider(
itemCount: () -> Int,
itemContent: @Composable (Int) -> Unit
- ): LazyLayoutItemProvider {
- return object : LazyLayoutItemProvider {
+ ): () -> LazyLayoutItemProvider {
+ val provider = object : LazyLayoutItemProvider {
@Composable
override fun Item(index: Int, key: Any) {
itemContent(index)
@@ -492,5 +492,6 @@
override val itemCount: Int get() = itemCount()
}
+ return { provider }
}
}
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt
index a3379dd..735e1e755 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text2/TextFieldKeyEventTest.kt
@@ -570,6 +570,7 @@
}
}
+ @Ignore // b/293919923
@Test
fun textField_withActiveSelection_shiftTabSingleLine() {
keysSequenceTest("text", singleLine = true) {
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt
index b4f0669..f9f10a3 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/AndroidSelectionHandles.android.kt
@@ -302,7 +302,7 @@
/**
* Computes whether the handle's appearance should be left-pointing or right-pointing.
*/
-private fun isLeft(
+internal fun isLeft(
isStartHandle: Boolean,
direction: ResolvedTextDirection,
handlesCrossed: Boolean
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.android.kt
new file mode 100644
index 0000000..c6183a9
--- /dev/null
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.android.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.selection
+
+import androidx.compose.foundation.text.Handle
+import androidx.compose.foundation.text.selection.DefaultSelectionHandle
+import androidx.compose.foundation.text.selection.HandleReferencePoint
+import androidx.compose.foundation.text.selection.SelectionHandleAnchor
+import androidx.compose.foundation.text.selection.SelectionHandleInfo
+import androidx.compose.foundation.text.selection.SelectionHandleInfoKey
+import androidx.compose.foundation.text.selection.isLeft
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.takeOrElse
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.style.ResolvedTextDirection
+import androidx.compose.ui.unit.IntOffset
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.round
+import androidx.compose.ui.window.Popup
+import androidx.compose.ui.window.PopupPositionProvider
+import androidx.compose.ui.window.PopupProperties
+
+@Composable
+internal actual fun TextFieldSelectionHandle2(
+ positionProvider: OffsetProvider,
+ isStartHandle: Boolean,
+ direction: ResolvedTextDirection,
+ handlesCrossed: Boolean,
+ modifier: Modifier
+) {
+ val isLeft = isLeft(isStartHandle, direction, handlesCrossed)
+ // The left selection handle's top right is placed at the given position, and vice versa.
+ val handleReferencePoint = if (isLeft) {
+ HandleReferencePoint.TopRight
+ } else {
+ HandleReferencePoint.TopLeft
+ }
+
+ HandlePopup2(
+ positionProvider = positionProvider,
+ handleReferencePoint = handleReferencePoint
+ ) {
+ DefaultSelectionHandle(
+ modifier = modifier
+ .semantics {
+ this[SelectionHandleInfoKey] = SelectionHandleInfo(
+ handle = if (isStartHandle) {
+ Handle.SelectionStart
+ } else {
+ Handle.SelectionEnd
+ },
+ position = positionProvider.provide(),
+ anchor = if (isLeft) {
+ SelectionHandleAnchor.Left
+ } else {
+ SelectionHandleAnchor.Right
+ }
+ )
+ },
+ isStartHandle = isStartHandle,
+ direction = direction,
+ handlesCrossed = handlesCrossed
+ )
+ }
+}
+
+/**
+ * An alternative HandlePopup API that uses dynamic positioning. This enables us to update the
+ * handle position when onGloballyPositioned is called.
+ */
+@Composable
+internal fun HandlePopup2(
+ positionProvider: OffsetProvider,
+ handleReferencePoint: HandleReferencePoint,
+ content: @Composable () -> Unit
+) {
+ val popupPositioner = remember(handleReferencePoint) {
+ HandlePositionProvider2(handleReferencePoint, positionProvider)
+ }
+
+ Popup(
+ popupPositionProvider = popupPositioner,
+ properties = PopupProperties(
+ excludeFromSystemGesture = true,
+ clippingEnabled = false
+ ),
+ content = content
+ )
+}
+
+internal class HandlePositionProvider2(
+ private val handleReferencePoint: HandleReferencePoint,
+ private val positionProvider: OffsetProvider
+) : PopupPositionProvider {
+
+ override fun calculatePosition(
+ anchorBounds: IntRect,
+ windowSize: IntSize,
+ layoutDirection: LayoutDirection,
+ popupContentSize: IntSize
+ ): IntOffset {
+ val intOffset = positionProvider.provide().takeOrElse {
+ Offset(Float.MAX_VALUE, Float.MAX_VALUE)
+ }.round()
+
+ return when (handleReferencePoint) {
+ HandleReferencePoint.TopLeft ->
+ IntOffset(
+ x = anchorBounds.left + intOffset.x,
+ y = anchorBounds.top + intOffset.y
+ )
+ HandleReferencePoint.TopRight ->
+ IntOffset(
+ x = anchorBounds.left + intOffset.x - popupContentSize.width,
+ y = anchorBounds.top + intOffset.y
+ )
+ HandleReferencePoint.TopMiddle ->
+ IntOffset(
+ x = anchorBounds.left + intOffset.x - popupContentSize.width / 2,
+ y = anchorBounds.top + intOffset.y
+ )
+ }
+ }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyItemScopeImpl.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyItemScopeImpl.kt
index 33940b8..cbc947b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyItemScopeImpl.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyItemScopeImpl.kt
@@ -22,20 +22,17 @@
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimationSpecsNode
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
-import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.LayoutModifierNode
import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.node.ParentDataModifierNode
import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
import kotlin.math.roundToInt
@@ -182,15 +179,15 @@
private data class AnimateItemElement(
val appearanceSpec: FiniteAnimationSpec<Float>?,
- val placementSpec: FiniteAnimationSpec<IntOffset>?,
-) : ModifierNodeElement<AnimateItemPlacementNode>() {
+ val placementSpec: FiniteAnimationSpec<IntOffset>?
+) : ModifierNodeElement<LazyLayoutAnimationSpecsNode>() {
- override fun create(): AnimateItemPlacementNode =
- AnimateItemPlacementNode(appearanceSpec, placementSpec)
+ override fun create(): LazyLayoutAnimationSpecsNode =
+ LazyLayoutAnimationSpecsNode(appearanceSpec, placementSpec)
- override fun update(node: AnimateItemPlacementNode) {
- node.delegatingNode.appearanceSpec = appearanceSpec
- node.delegatingNode.placementSpec = placementSpec
+ override fun update(node: LazyLayoutAnimationSpecsNode) {
+ node.appearanceSpec = appearanceSpec
+ node.placementSpec = placementSpec
}
override fun InspectorInfo.inspectableProperties() {
@@ -199,18 +196,3 @@
value = placementSpec
}
}
-
-private class AnimateItemPlacementNode(
- appearanceSpec: FiniteAnimationSpec<Float>?,
- placementSpec: FiniteAnimationSpec<IntOffset>?,
-) : DelegatingNode(), ParentDataModifierNode {
-
- val delegatingNode = delegate(
- LazyLayoutAnimateItemModifierNode(
- appearanceSpec,
- placementSpec
- )
- )
-
- override fun Density.modifyParentData(parentData: Any?): Any = delegatingNode
-}
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 d9f7585..ca072ec 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
@@ -292,7 +292,8 @@
spacing = spacing,
visualOffset = visualItemOffset,
key = key,
- contentType = contentType
+ contentType = contentType,
+ animator = state.itemAnimator
)
}
}
@@ -341,6 +342,9 @@
hasLookaheadPassOccurred = hasLookaheadPassOccurred,
isLookingAhead = isLookingAhead,
postLookaheadLayoutInfo = state.postLookaheadLayoutInfo,
+ coroutineScope = requireNotNull(state.coroutineScope) {
+ "coroutineScope should be not null"
+ },
layout = { width, height, placement ->
layout(
containerConstraints.constrainWidth(width + totalHorizontalPadding),
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemAnimator.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemAnimator.kt
index 023c327..978c87b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemAnimator.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListItemAnimator.kt
@@ -16,11 +16,13 @@
package androidx.compose.foundation.lazy
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimation
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimationSpecsNode
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastForEach
+import kotlinx.coroutines.CoroutineScope
/**
* Handles the item animations when it is set via [LazyItemScope.animateItemPlacement].
@@ -28,11 +30,11 @@
* This class is responsible for:
* - animating item appearance for the new items.
* - detecting when item position changed, figuring our start/end offsets and starting the
- * animations for placement animations. *
+ * animations for placement animations.
*/
internal class LazyListItemAnimator {
- // contains the keys of the active items with animation node.
- private val activeKeys = mutableSetOf<Any>()
+ // state containing relevant info for active items.
+ private val keyToItemInfoMap = mutableMapOf<Any, ItemInfo>()
// snapshot of the key to index map used for the last measuring.
private var keyIndexMap: LazyLayoutKeyIndexMap? = null
@@ -60,14 +62,15 @@
itemProvider: LazyListMeasuredItemProvider,
isVertical: Boolean,
isLookingAhead: Boolean,
- hasLookaheadOccurred: Boolean
+ hasLookaheadOccurred: Boolean,
+ coroutineScope: CoroutineScope
) {
val previousKeyToIndexMap = this.keyIndexMap
val keyIndexMap = itemProvider.keyIndexMap
this.keyIndexMap = keyIndexMap
val hasAnimations = positionedItems.fastAny { it.hasAnimations }
- if (!hasAnimations && activeKeys.isEmpty()) {
+ if (!hasAnimations && keyToItemInfoMap.isEmpty()) {
// no animations specified - no work needed
reset()
return
@@ -89,14 +92,18 @@
// means lookahead pass, or regular pass when not in a lookahead scope.
val shouldSetupAnimation = isLookingAhead || !hasLookaheadOccurred
// first add all items we had in the previous run
- movingAwayKeys.addAll(activeKeys)
+ movingAwayKeys.addAll(keyToItemInfoMap.keys)
// iterate through the items which are visible (without animated offsets)
positionedItems.fastForEach { item ->
// remove items we have in the current one as they are still visible.
movingAwayKeys.remove(item.key)
if (item.hasAnimations) {
- if (!activeKeys.contains(item.key)) {
- activeKeys += item.key
+ val itemInfo = keyToItemInfoMap[item.key]
+ // there is no state associated with this item yet
+ if (itemInfo == null) {
+ val newItemInfo = ItemInfo()
+ newItemInfo.updateAnimation(item, coroutineScope)
+ keyToItemInfoMap[item.key] = newItemInfo
val previousIndex = previousKeyToIndexMap?.getIndex(item.key) ?: -1
if (item.index != previousIndex && previousIndex != -1) {
if (previousIndex < previousFirstVisibleIndex) {
@@ -106,22 +113,25 @@
movingInFromEndBound.add(item)
}
} else {
- initializeNode(
+ initializeAnimation(
item,
- item.getOffset(0).let { if (item.isVertical) it.y else it.x }
+ item.getOffset(0).let { if (item.isVertical) it.y else it.x },
+ newItemInfo
)
if (previousIndex == -1 && previousKeyToIndexMap != null) {
- item.forEachNode { _, node ->
- node.animateAppearance()
+ newItemInfo.animations.forEach {
+ it?.animateAppearance()
}
}
}
} else {
if (shouldSetupAnimation) {
- item.forEachNode { _, node ->
- if (node.rawOffset != LazyLayoutAnimateItemModifierNode.NotInitialized
+ itemInfo.updateAnimation(item, coroutineScope)
+ itemInfo.animations.forEach { animation ->
+ if (animation != null &&
+ animation.rawOffset != LazyLayoutAnimation.NotInitialized
) {
- node.rawOffset += scrollOffset
+ animation.rawOffset += scrollOffset
}
}
startPlacementAnimationsIfNeeded(item)
@@ -129,7 +139,7 @@
}
} else {
// no animation, clean up if needed
- activeKeys.remove(item.key)
+ keyToItemInfoMap.remove(item.key)
}
}
@@ -139,7 +149,7 @@
movingInFromStartBound.fastForEach { item ->
accumulatedOffset += item.size
val mainAxisOffset = 0 - accumulatedOffset
- initializeNode(item, mainAxisOffset)
+ initializeAnimation(item, mainAxisOffset)
startPlacementAnimationsIfNeeded(item)
}
accumulatedOffset = 0
@@ -147,7 +157,7 @@
movingInFromEndBound.fastForEach { item ->
val mainAxisOffset = mainAxisLayoutSize + accumulatedOffset
accumulatedOffset += item.size
- initializeNode(item, mainAxisOffset)
+ initializeAnimation(item, mainAxisOffset)
startPlacementAnimationsIfNeeded(item)
}
}
@@ -158,19 +168,15 @@
val newIndex = keyIndexMap.getIndex(key)
if (newIndex == -1) {
- activeKeys.remove(key)
+ keyToItemInfoMap.remove(key)
} else {
val item = itemProvider.getAndMeasure(newIndex)
+ val itemInfo = keyToItemInfoMap.getValue(key)
// check if we have any active placement animation on the item
- var inProgress = false
- repeat(item.placeablesCount) {
- if (item.getParentData(it).node?.isPlacementAnimationInProgress == true) {
- inProgress = true
- return@repeat
- }
- }
+ val inProgress =
+ itemInfo.animations.any { it?.isPlacementAnimationInProgress == true }
if ((!inProgress && newIndex == previousKeyToIndexMap?.getIndex(key))) {
- activeKeys.remove(key)
+ keyToItemInfoMap.remove(key)
} else {
if (newIndex < firstVisibleIndex) {
movingAwayToStartBound.add(item)
@@ -222,14 +228,15 @@
* for example when we snap to a new position.
*/
fun reset() {
- activeKeys.clear()
+ keyToItemInfoMap.clear()
keyIndexMap = LazyLayoutKeyIndexMap.Empty
firstVisibleIndex = -1
}
- private fun initializeNode(
+ private fun initializeAnimation(
item: LazyListMeasuredItem,
- mainAxisOffset: Int
+ mainAxisOffset: Int,
+ itemInfo: ItemInfo = keyToItemInfoMap.getValue(item.key)
) {
val firstPlaceableOffset = item.getOffset(0)
@@ -240,39 +247,77 @@
}
// initialize offsets
- item.forEachNode { placeableIndex, node ->
- val diffToFirstPlaceableOffset =
- item.getOffset(placeableIndex) - firstPlaceableOffset
- node.rawOffset = targetFirstPlaceableOffset + diffToFirstPlaceableOffset
+ itemInfo.animations.forEachIndexed { placeableIndex, animation ->
+ if (animation != null) {
+ val diffToFirstPlaceableOffset =
+ item.getOffset(placeableIndex) - firstPlaceableOffset
+ animation.rawOffset = targetFirstPlaceableOffset + diffToFirstPlaceableOffset
+ }
}
}
private fun startPlacementAnimationsIfNeeded(item: LazyListMeasuredItem) {
- item.forEachNode { placeableIndex, node ->
- val newTarget = item.getOffset(placeableIndex)
- val currentTarget = node.rawOffset
- if (currentTarget != LazyLayoutAnimateItemModifierNode.NotInitialized &&
- currentTarget != newTarget
- ) {
- node.animatePlacementDelta(newTarget - currentTarget)
+ val itemInfo = keyToItemInfoMap.getValue(item.key)
+ itemInfo.animations.forEachIndexed { placeableIndex, animation ->
+ if (animation != null) {
+ val newTarget = item.getOffset(placeableIndex)
+ val currentTarget = animation.rawOffset
+ if (currentTarget != LazyLayoutAnimation.NotInitialized &&
+ currentTarget != newTarget
+ ) {
+ animation.animatePlacementDelta(newTarget - currentTarget)
+ }
+ animation.rawOffset = newTarget
}
- node.rawOffset = newTarget
}
}
- private val Any?.node get() = this as? LazyLayoutAnimateItemModifierNode
+ fun getAnimation(key: Any, placeableIndex: Int): LazyLayoutAnimation? =
+ keyToItemInfoMap[key]?.animations?.get(placeableIndex)
private val LazyListMeasuredItem.hasAnimations: Boolean
get() {
- forEachNode { _, _ -> return true }
+ repeat(placeablesCount) { index ->
+ getParentData(index).specs?.let {
+ // found at least one
+ return true
+ }
+ }
return false
}
- private inline fun LazyListMeasuredItem.forEachNode(
- block: (placeableIndex: Int, node: LazyLayoutAnimateItemModifierNode) -> Unit
- ) {
- repeat(placeablesCount) { index ->
- getParentData(index).node?.let { block(index, it) }
+ private class ItemInfo {
+ /**
+ * This array will have the same amount of elements as there are placeables on the item.
+ * If the element is not null this means there are specs associated with the given placeable.
+ */
+ var animations = EmptyArray
+ private set
+
+ fun updateAnimation(positionedItem: LazyListMeasuredItem, coroutineScope: CoroutineScope) {
+ for (i in positionedItem.placeablesCount until animations.size) {
+ animations[i]?.stopAnimations()
+ }
+ if (animations.size != positionedItem.placeablesCount) {
+ animations = animations.copyOf(positionedItem.placeablesCount)
+ }
+ repeat(positionedItem.placeablesCount) { index ->
+ val specs = positionedItem.getParentData(index).specs
+ if (specs == null) {
+ animations[index]?.stopAnimations()
+ animations[index] = null
+ } else {
+ val animation = animations[index] ?: LazyLayoutAnimation(coroutineScope).also {
+ animations[index] = it
+ }
+ animation.appearanceSpec = specs.appearanceSpec
+ animation.placementSpec = specs.placementSpec
+ }
+ }
}
}
}
+
+private val Any?.specs get() = this as? LazyLayoutAnimationSpecsNode
+
+private val EmptyArray = emptyArray<LazyLayoutAnimation?>()
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 3876e05..6402fc2 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
@@ -33,6 +33,7 @@
import kotlin.math.abs
import kotlin.math.roundToInt
import kotlin.math.sign
+import kotlinx.coroutines.CoroutineScope
/**
* Measures and calculates the positions for the requested items. The result is produced
@@ -62,6 +63,7 @@
hasLookaheadPassOccurred: Boolean,
isLookingAhead: Boolean,
postLookaheadLayoutInfo: LazyListLayoutInfo?,
+ coroutineScope: CoroutineScope,
@Suppress("PrimitiveInLambda")
layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
): LazyListMeasureResult {
@@ -79,7 +81,8 @@
itemProvider = measuredItemProvider,
isVertical = isVertical,
isLookingAhead = isLookingAhead,
- hasLookaheadOccurred = hasLookaheadPassOccurred
+ hasLookaheadOccurred = hasLookaheadPassOccurred,
+ coroutineScope = coroutineScope
)
return LazyListMeasureResult(
firstVisibleItem = null,
@@ -321,7 +324,8 @@
itemProvider = measuredItemProvider,
isVertical = isVertical,
isLookingAhead = isLookingAhead,
- hasLookaheadOccurred = hasLookaheadPassOccurred
+ hasLookaheadOccurred = hasLookaheadPassOccurred,
+ coroutineScope = coroutineScope
)
val headerItem = if (headerIndexes.isNotEmpty()) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt
index 3420577..24a1642 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyListMeasuredItem.kt
@@ -17,8 +17,8 @@
package androidx.compose.foundation.lazy
import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode.Companion.NotInitialized
+import androidx.compose.foundation.lazy.layout.DefaultLayerBlock
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimation.Companion.NotInitialized
import androidx.compose.ui.Alignment
import androidx.compose.ui.graphics.GraphicsLayerScope
import androidx.compose.ui.layout.Placeable
@@ -52,7 +52,8 @@
*/
private val visualOffset: IntOffset,
override val key: Any,
- override val contentType: Any?
+ override val contentType: Any?,
+ private val animator: LazyListItemAnimator
) : LazyListItemInfo {
override var offset: Int = 0
private set
@@ -144,30 +145,30 @@
val minOffset = minMainAxisOffset - placeable.mainAxisSize
val maxOffset = maxMainAxisOffset
var offset = getOffset(index)
- val animateNode = getParentData(index) as? LazyLayoutAnimateItemModifierNode
+ val animation = animator.getAnimation(key, index)
val layerBlock: GraphicsLayerScope.() -> Unit
- if (animateNode != null) {
+ if (animation != null) {
if (isLookingAhead) {
// Skip animation in lookahead pass
- animateNode.lookaheadOffset = offset
+ animation.lookaheadOffset = offset
} else {
- val targetOffset = if (animateNode.lookaheadOffset != NotInitialized) {
- animateNode.lookaheadOffset
+ val targetOffset = if (animation.lookaheadOffset != NotInitialized) {
+ animation.lookaheadOffset
} else {
offset
}
- val animatedOffset = targetOffset + animateNode.placementDelta
+ val animatedOffset = targetOffset + animation.placementDelta
// cancel the animation if current and target offsets are both out of the bounds
if ((targetOffset.mainAxis <= minOffset &&
animatedOffset.mainAxis <= minOffset) ||
(targetOffset.mainAxis >= maxOffset &&
animatedOffset.mainAxis >= maxOffset)
) {
- animateNode.cancelPlacementAnimation()
+ animation.cancelPlacementAnimation()
}
offset = animatedOffset
}
- layerBlock = animateNode
+ layerBlock = animation
} else {
layerBlock = DefaultLayerBlock
}
@@ -192,8 +193,3 @@
}
private const val Unset = Int.MIN_VALUE
-
-/**
- * Block on [GraphicsLayerScope] which applies the default layer parameters.
- */
-private val DefaultLayerBlock: GraphicsLayerScope.() -> Unit = {}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
index ff95f02..327f8e1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGrid.kt
@@ -34,6 +34,7 @@
import androidx.compose.foundation.overscroll
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.MeasureResult
@@ -47,6 +48,7 @@
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.offset
import androidx.compose.ui.util.fastForEach
+import kotlinx.coroutines.CoroutineScope
@OptIn(ExperimentalFoundationApi::class)
@Composable
@@ -80,6 +82,7 @@
val semanticState = rememberLazyGridSemanticState(state, reverseLayout)
+ val coroutineScope = rememberCoroutineScope()
val measurePolicy = rememberLazyGridMeasurePolicy(
itemProviderLambda,
state,
@@ -89,6 +92,7 @@
isVertical,
horizontalArrangement,
verticalArrangement,
+ coroutineScope
)
state.isVertical = isVertical
@@ -167,10 +171,12 @@
reverseLayout: Boolean,
/** The layout orientation of the list */
isVertical: Boolean,
- /** The horizontal arrangement for items. Required when isVertical is false */
- horizontalArrangement: Arrangement.Horizontal? = null,
- /** The vertical arrangement for items. Required when isVertical is true */
- verticalArrangement: Arrangement.Vertical? = null,
+ /** The horizontal arrangement for items */
+ horizontalArrangement: Arrangement.Horizontal?,
+ /** The vertical arrangement for items */
+ verticalArrangement: Arrangement.Vertical?,
+ /** Coroutine scope for item animations */
+ coroutineScope: CoroutineScope
) = remember<LazyLayoutMeasureScope.(Constraints) -> MeasureResult>(
state,
slots,
@@ -281,7 +287,8 @@
afterContentPadding = afterContentPadding,
visualOffset = visualItemOffset,
placeables = placeables,
- contentType = contentType
+ contentType = contentType,
+ animator = state.placementAnimator
)
}
val measuredLineProvider = object : LazyGridMeasuredLineProvider(
@@ -363,6 +370,7 @@
placementAnimator = state.placementAnimator,
spanLayoutProvider = spanLayoutProvider,
pinnedItems = pinnedItems,
+ coroutineScope = coroutineScope,
layout = { width, height, placement ->
layout(
containerConstraints.constrainWidth(width + totalHorizontalPadding),
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt
index 58be76c..19d1f00 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemPlacementAnimator.kt
@@ -16,12 +16,14 @@
package androidx.compose.foundation.lazy.grid
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimation
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimationSpecsNode
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastForEach
+import kotlinx.coroutines.CoroutineScope
/**
* Handles the item placement animations when it is set via [LazyGridItemScope.animateItemPlacement].
@@ -58,7 +60,8 @@
positionedItems: MutableList<LazyGridMeasuredItem>,
itemProvider: LazyGridMeasuredItemProvider,
spanLayoutProvider: LazyGridSpanLayoutProvider,
- isVertical: Boolean
+ isVertical: Boolean,
+ coroutineScope: CoroutineScope
) {
if (!positionedItems.fastAny { it.hasAnimations } && keyToItemInfoMap.isEmpty()) {
// no animations specified - no work needed
@@ -90,8 +93,9 @@
val itemInfo = keyToItemInfoMap[item.key]
// there is no state associated with this item yet
if (itemInfo == null) {
- keyToItemInfoMap[item.key] =
- ItemInfo(item.crossAxisSize, item.crossAxisOffset)
+ val newItemInfo = ItemInfo(item.crossAxisSize, item.crossAxisOffset)
+ newItemInfo.updateAnimation(item, coroutineScope)
+ keyToItemInfoMap[item.key] = newItemInfo
val previousIndex = previousKeyToIndexMap.getIndex(item.key)
if (previousIndex != -1 && item.index != previousIndex) {
if (previousIndex < previousFirstVisibleIndex) {
@@ -101,15 +105,18 @@
movingInFromEndBound.add(item)
}
} else {
- initializeNode(
+ initializeAnimation(
item,
- item.offset.let { if (item.isVertical) it.y else it.x }
+ item.offset.let { if (item.isVertical) it.y else it.x },
+ newItemInfo
)
}
} else {
- item.forEachNode {
- if (it.rawOffset != LazyLayoutAnimateItemModifierNode.NotInitialized) {
- it.rawOffset += scrollOffset
+ itemInfo.animations.forEach { animation ->
+ if (animation != null &&
+ animation.rawOffset != LazyLayoutAnimation.NotInitialized
+ ) {
+ animation.rawOffset += scrollOffset
}
}
itemInfo.crossAxisSize = item.crossAxisSize
@@ -136,7 +143,7 @@
previousLine = line
}
val mainAxisOffset = 0 - accumulatedOffset - item.mainAxisSize
- initializeNode(item, mainAxisOffset)
+ initializeAnimation(item, mainAxisOffset)
startAnimationsIfNeeded(item)
}
accumulatedOffset = 0
@@ -153,7 +160,7 @@
previousLine = line
}
val mainAxisOffset = mainAxisLayoutSize + accumulatedOffset
- initializeNode(item, mainAxisOffset)
+ initializeAnimation(item, mainAxisOffset)
startAnimationsIfNeeded(item)
}
@@ -175,13 +182,8 @@
}
)
// check if we have any active placement animation on the item
- var inProgress = false
- repeat(item.placeablesCount) {
- if (item.getParentData(it).node?.isPlacementAnimationInProgress == true) {
- inProgress = true
- return@repeat
- }
- }
+ val inProgress =
+ itemInfo.animations.any { it?.isPlacementAnimationInProgress == true }
if ((!inProgress && newIndex == previousKeyToIndexMap.getIndex(key))) {
keyToItemInfoMap.remove(key)
} else {
@@ -264,9 +266,10 @@
firstVisibleIndex = -1
}
- private fun initializeNode(
+ private fun initializeAnimation(
item: LazyGridMeasuredItem,
- mainAxisOffset: Int
+ mainAxisOffset: Int,
+ itemInfo: ItemInfo = keyToItemInfoMap.getValue(item.key)
) {
val firstPlaceableOffset = item.offset
@@ -277,44 +280,80 @@
}
// initialize offsets
- item.forEachNode { node ->
- val diffToFirstPlaceableOffset =
- item.offset - firstPlaceableOffset
- node.rawOffset = targetFirstPlaceableOffset + diffToFirstPlaceableOffset
+ itemInfo.animations.forEach { animation ->
+ if (animation != null) {
+ val diffToFirstPlaceableOffset =
+ item.offset - firstPlaceableOffset
+ animation.rawOffset = targetFirstPlaceableOffset + diffToFirstPlaceableOffset
+ }
}
}
private fun startAnimationsIfNeeded(item: LazyGridMeasuredItem) {
- item.forEachNode { node ->
- val newTarget = item.offset
- val currentTarget = node.rawOffset
- if (currentTarget != LazyLayoutAnimateItemModifierNode.NotInitialized &&
- currentTarget != newTarget
- ) {
- node.animatePlacementDelta(newTarget - currentTarget)
+ val itemInfo = keyToItemInfoMap.getValue(item.key)
+ itemInfo.animations.forEach { animation ->
+ if (animation != null) {
+ val newTarget = item.offset
+ val currentTarget = animation.rawOffset
+ if (currentTarget != LazyLayoutAnimation.NotInitialized &&
+ currentTarget != newTarget
+ ) {
+ animation.animatePlacementDelta(newTarget - currentTarget)
+ }
+ animation.rawOffset = newTarget
}
- node.rawOffset = newTarget
}
}
- private val Any?.node get() = this as? LazyLayoutAnimateItemModifierNode
+ fun getAnimation(key: Any, placeableIndex: Int): LazyLayoutAnimation? =
+ keyToItemInfoMap[key]?.animations?.get(placeableIndex)
private val LazyGridMeasuredItem.hasAnimations: Boolean
get() {
- forEachNode { return true }
+ repeat(placeablesCount) { index ->
+ getParentData(index).specs?.let {
+ // found at least one
+ return true
+ }
+ }
return false
}
-
- private inline fun LazyGridMeasuredItem.forEachNode(
- block: (LazyLayoutAnimateItemModifierNode) -> Unit
- ) {
- repeat(placeablesCount) { index ->
- getParentData(index).node?.let(block)
- }
- }
}
private class ItemInfo(
var crossAxisSize: Int,
var crossAxisOffset: Int
-)
+) {
+ /**
+ * This array will have the same amount of elements as there are placeables on the item.
+ * If the element is not null this means there are specs associated with the given placeable.
+ */
+ var animations = EmptyArray
+ private set
+
+ fun updateAnimation(positionedItem: LazyGridMeasuredItem, coroutineScope: CoroutineScope) {
+ for (i in positionedItem.placeablesCount until animations.size) {
+ animations[i]?.stopAnimations()
+ }
+ if (animations.size != positionedItem.placeablesCount) {
+ animations = animations.copyOf(positionedItem.placeablesCount)
+ }
+ repeat(positionedItem.placeablesCount) { index ->
+ val specs = positionedItem.getParentData(index).specs
+ if (specs == null) {
+ animations[index]?.stopAnimations()
+ animations[index] = null
+ } else {
+ val item = animations[index] ?: LazyLayoutAnimation(coroutineScope).also {
+ animations[index] = it
+ }
+ item.appearanceSpec = specs.appearanceSpec
+ item.placementSpec = specs.placementSpec
+ }
+ }
+ }
+}
+
+private val Any?.specs get() = this as? LazyLayoutAnimationSpecsNode
+
+private val EmptyArray = emptyArray<LazyLayoutAnimation?>()
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScopeImpl.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScopeImpl.kt
index ea43720..bfda57e 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScopeImpl.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridItemScopeImpl.kt
@@ -18,53 +18,32 @@
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimationSpecsNode
import androidx.compose.ui.Modifier
-import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.node.ParentDataModifierNode
import androidx.compose.ui.platform.InspectorInfo
-import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
@OptIn(ExperimentalFoundationApi::class)
internal object LazyGridItemScopeImpl : LazyGridItemScope {
@ExperimentalFoundationApi
override fun Modifier.animateItemPlacement(animationSpec: FiniteAnimationSpec<IntOffset>) =
- this then AnimateItemPlacementElement(animationSpec)
+ this then AnimateItemElement(animationSpec)
}
-private class AnimateItemPlacementElement(
- val animationSpec: FiniteAnimationSpec<IntOffset>
-) : ModifierNodeElement<AnimateItemPlacementNode>() {
+private data class AnimateItemElement(
+ val placementSpec: FiniteAnimationSpec<IntOffset>
+) : ModifierNodeElement<LazyLayoutAnimationSpecsNode>() {
- override fun create(): AnimateItemPlacementNode = AnimateItemPlacementNode(animationSpec)
+ override fun create(): LazyLayoutAnimationSpecsNode =
+ LazyLayoutAnimationSpecsNode(null, placementSpec)
- override fun update(node: AnimateItemPlacementNode) {
- node.delegatingNode.placementSpec = animationSpec
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (other !is AnimateItemPlacementElement) return false
- return animationSpec != other.animationSpec
- }
-
- override fun hashCode(): Int {
- return animationSpec.hashCode()
+ override fun update(node: LazyLayoutAnimationSpecsNode) {
+ node.placementSpec = placementSpec
}
override fun InspectorInfo.inspectableProperties() {
name = "animateItemPlacement"
- value = animationSpec
+ value = placementSpec
}
}
-
-private class AnimateItemPlacementNode(
- animationSpec: FiniteAnimationSpec<IntOffset>
-) : DelegatingNode(), ParentDataModifierNode {
-
- val delegatingNode = delegate(LazyLayoutAnimateItemModifierNode(null, animationSpec))
-
- override fun Density.modifyParentData(parentData: Any?): Any = delegatingNode
-}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
index f768d21..07c9edb 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasure.kt
@@ -33,6 +33,7 @@
import kotlin.math.min
import kotlin.math.roundToInt
import kotlin.math.sign
+import kotlinx.coroutines.CoroutineScope
/**
* Measures and calculates the positions for the currently visible items. The result is produced
@@ -59,6 +60,7 @@
placementAnimator: LazyGridItemPlacementAnimator,
spanLayoutProvider: LazyGridSpanLayoutProvider,
pinnedItems: List<Int>,
+ coroutineScope: CoroutineScope,
layout: (Int, Int, Placeable.PlacementScope.() -> Unit) -> MeasureResult
): LazyGridMeasureResult {
require(beforeContentPadding >= 0) { "negative beforeContentPadding" }
@@ -270,7 +272,8 @@
positionedItems = positionedItems,
itemProvider = measuredItemProvider,
spanLayoutProvider = spanLayoutProvider,
- isVertical = isVertical
+ isVertical = isVertical,
+ coroutineScope = coroutineScope
)
return LazyGridMeasureResult(
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt
index 3b698b1..961341b 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/grid/LazyGridMeasuredItem.kt
@@ -16,7 +16,6 @@
package androidx.compose.foundation.lazy.grid
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
@@ -47,7 +46,8 @@
* value passed into the place() call.
*/
private val visualOffset: IntOffset,
- override val contentType: Any?
+ override val contentType: Any?,
+ private val animator: LazyGridItemPlacementAnimator
) : LazyGridItemInfo {
/**
* Main axis size of the item - the max main axis size of the placeables.
@@ -133,14 +133,14 @@
val maxOffset = maxMainAxisOffset
var offset = offset
- val animateNode = getParentData(index) as? LazyLayoutAnimateItemModifierNode
- if (animateNode != null) {
- val animatedOffset = offset + animateNode.placementDelta
+ val animation = animator.getAnimation(key, index)
+ if (animation != null) {
+ val animatedOffset = offset + animation.placementDelta
// cancel the animation if current and target offsets are both out of the bounds.
if ((offset.mainAxis <= minOffset && animatedOffset.mainAxis <= minOffset) ||
(offset.mainAxis >= maxOffset && animatedOffset.mainAxis >= maxOffset)
) {
- animateNode.cancelPlacementAnimation()
+ animation.cancelPlacementAnimation()
}
offset = animatedOffset
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt
index 3ad7f4f..6c08e89 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayout.kt
@@ -37,6 +37,12 @@
* @param prefetchState allows to schedule items for prefetching
* @param measurePolicy Measure policy which allows to only compose and measure needed items.
*/
+@Deprecated(
+ message = "Use an overload accepting a lambda prodicing an item provider instead",
+ replaceWith = ReplaceWith(
+ "LazyLayout({ itemProvider }, modifier, prefetchState, measurePolicy)"
+ )
+)
@ExperimentalFoundationApi
@Composable
fun LazyLayout(
@@ -48,9 +54,19 @@
LazyLayout({ itemProvider }, modifier, prefetchState, measurePolicy)
}
+/**
+ * A layout that only composes and lays out currently needed items. Can be used to build
+ * efficient scrollable layouts.
+ *
+ * @param itemProvider lambda producing an item provider containing all the needed info about
+ * the items which could be used to compose and measure items as part of [measurePolicy].
+ * @param modifier to apply on the layout
+ * @param prefetchState allows to schedule items for prefetching
+ * @param measurePolicy Measure policy which allows to only compose and measure needed items.
+ */
@ExperimentalFoundationApi
@Composable
-internal fun LazyLayout(
+fun LazyLayout(
itemProvider: () -> LazyLayoutItemProvider,
modifier: Modifier = Modifier,
prefetchState: LazyLayoutPrefetchState? = null,
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutAnimateItemModifierNode.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutAnimation.kt
similarity index 84%
rename from compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutAnimateItemModifierNode.kt
rename to compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutAnimation.kt
index aeb8a58..0dd7231 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutAnimateItemModifierNode.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/layout/LazyLayoutAnimation.kt
@@ -29,14 +29,19 @@
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.GraphicsLayerScope
+import androidx.compose.ui.node.ParentDataModifierNode
+import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
-internal class LazyLayoutAnimateItemModifierNode(
- var appearanceSpec: FiniteAnimationSpec<Float>?,
- var placementSpec: FiniteAnimationSpec<IntOffset>?
-) : Modifier.Node(), (GraphicsLayerScope) -> Unit {
+internal class LazyLayoutAnimation(
+ val coroutineScope: CoroutineScope
+) : (GraphicsLayerScope) -> Unit {
+
+ var appearanceSpec: FiniteAnimationSpec<Float>? = null
+ var placementSpec: FiniteAnimationSpec<IntOffset>? = null
/**
* Returns true when the placement animation is currently in progress so the parent
@@ -153,13 +158,22 @@
}
}
- override fun onDetach() {
+ fun stopAnimations() {
+ if (isPlacementAnimationInProgress) {
+ isPlacementAnimationInProgress = false
+ coroutineScope.launch {
+ placementDeltaAnimation.stop()
+ }
+ }
+ if (isAppearanceAnimationInProgress) {
+ isAppearanceAnimationInProgress = false
+ coroutineScope.launch {
+ visibilityAnimation.stop()
+ }
+ }
placementDelta = IntOffset.Zero
- isPlacementAnimationInProgress = false
rawOffset = NotInitialized
visibility = 1f
- isAppearanceAnimationInProgress = false
- // animations will be canceled because coroutineScope will be canceled.
}
override fun invoke(scope: GraphicsLayerScope) {
@@ -171,6 +185,13 @@
}
}
+internal class LazyLayoutAnimationSpecsNode(
+ var appearanceSpec: FiniteAnimationSpec<Float>?,
+ var placementSpec: FiniteAnimationSpec<IntOffset>?
+) : Modifier.Node(), ParentDataModifierNode {
+ override fun Density.modifyParentData(parentData: Any?): Any = this@LazyLayoutAnimationSpecsNode
+}
+
/**
* We switch to this spec when a duration based animation is being interrupted.
*/
@@ -178,3 +199,8 @@
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntOffset.VisibilityThreshold
)
+
+/**
+ * Block on [GraphicsLayerScope] which applies the default layer parameters.
+ */
+internal val DefaultLayerBlock: GraphicsLayerScope.() -> Unit = {}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGrid.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGrid.kt
index 8eb1453..f92fcc3 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGrid.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGrid.kt
@@ -28,6 +28,7 @@
import androidx.compose.foundation.lazy.layout.lazyLayoutSemantics
import androidx.compose.foundation.overscroll
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Constraints
@@ -64,6 +65,7 @@
val overscrollEffect = ScrollableDefaults.overscrollEffect()
val itemProviderLambda = rememberStaggeredGridItemProviderLambda(state, content)
+ val coroutineScope = rememberCoroutineScope()
val measurePolicy = rememberStaggeredGridMeasurePolicy(
state,
itemProviderLambda,
@@ -72,6 +74,7 @@
orientation,
mainAxisSpacing,
crossAxisSpacing,
+ coroutineScope,
slots,
)
val semanticState = rememberLazyStaggeredGridSemanticState(state, reverseLayout)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemPlacementAnimator.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemPlacementAnimator.kt
index b46ca41..36d466d 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemPlacementAnimator.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemPlacementAnimator.kt
@@ -16,11 +16,13 @@
package androidx.compose.foundation.lazy.staggeredgrid
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimation
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimationSpecsNode
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastForEach
+import kotlinx.coroutines.CoroutineScope
/**
* Handles the item placement animations when it is set via
@@ -58,7 +60,8 @@
positionedItems: MutableList<LazyStaggeredGridMeasuredItem>,
itemProvider: LazyStaggeredGridMeasureProvider,
isVertical: Boolean,
- laneCount: Int
+ laneCount: Int,
+ coroutineScope: CoroutineScope
) {
if (!positionedItems.fastAny { it.hasAnimations } && keyToItemInfoMap.isEmpty()) {
// no animations specified - no work needed
@@ -90,8 +93,9 @@
val itemInfo = keyToItemInfoMap[item.key]
// there is no state associated with this item yet
if (itemInfo == null) {
- keyToItemInfoMap[item.key] =
- ItemInfo(item.lane, item.span, item.crossAxisOffset)
+ val newItemInfo = ItemInfo(item.lane, item.span, item.crossAxisOffset)
+ newItemInfo.updateAnimation(item, coroutineScope)
+ keyToItemInfoMap[item.key] = newItemInfo
val previousIndex = previousKeyToIndexMap.getIndex(item.key)
if (previousIndex != -1 && item.index != previousIndex) {
if (previousIndex < previousFirstVisibleIndex) {
@@ -101,15 +105,18 @@
movingInFromEndBound.add(item)
}
} else {
- initializeNode(
+ initializeAnimation(
item,
- item.offset.let { if (item.isVertical) it.y else it.x }
+ item.offset.let { if (item.isVertical) it.y else it.x },
+ newItemInfo
)
}
} else {
- item.forEachNode {
- if (it.rawOffset != LazyLayoutAnimateItemModifierNode.NotInitialized) {
- it.rawOffset += scrollOffset
+ itemInfo.animations.forEach { animation ->
+ if (animation != null &&
+ animation.rawOffset != LazyLayoutAnimation.NotInitialized
+ ) {
+ animation.rawOffset += scrollOffset
}
}
itemInfo.lane = item.lane
@@ -129,7 +136,7 @@
movingInFromStartBound.fastForEach { item ->
accumulatedOffsetPerLane[item.lane] += item.mainAxisSize
val mainAxisOffset = 0 - accumulatedOffsetPerLane[item.lane]
- initializeNode(item, mainAxisOffset)
+ initializeAnimation(item, mainAxisOffset)
startAnimationsIfNeeded(item)
}
accumulatedOffsetPerLane.fill(0)
@@ -139,7 +146,7 @@
movingInFromEndBound.fastForEach { item ->
val mainAxisOffset = mainAxisLayoutSize + accumulatedOffsetPerLane[item.lane]
accumulatedOffsetPerLane[item.lane] += item.mainAxisSize
- initializeNode(item, mainAxisOffset)
+ initializeAnimation(item, mainAxisOffset)
startAnimationsIfNeeded(item)
}
accumulatedOffsetPerLane.fill(0)
@@ -159,13 +166,8 @@
SpanRange(itemInfo.lane, itemInfo.span)
)
// check if we have any active placement animation on the item
- var inProgress = false
- repeat(item.placeablesCount) {
- if (item.getParentData(it).node?.isPlacementAnimationInProgress == true) {
- inProgress = true
- return@repeat
- }
- }
+ val inProgress =
+ itemInfo.animations.any { it?.isPlacementAnimationInProgress == true }
if ((!inProgress && newIndex == previousKeyToIndexMap.getIndex(key))) {
keyToItemInfoMap.remove(key)
} else {
@@ -221,9 +223,10 @@
firstVisibleIndex = -1
}
- private fun initializeNode(
+ private fun initializeAnimation(
item: LazyStaggeredGridMeasuredItem,
- mainAxisOffset: Int
+ mainAxisOffset: Int,
+ itemInfo: ItemInfo = keyToItemInfoMap.getValue(item.key)
) {
val firstPlaceableOffset = item.offset
@@ -234,45 +237,84 @@
}
// initialize offsets
- item.forEachNode { node ->
- val diffToFirstPlaceableOffset =
- item.offset - firstPlaceableOffset
- node.rawOffset = targetFirstPlaceableOffset + diffToFirstPlaceableOffset
+ itemInfo.animations.forEach { animation ->
+ if (animation != null) {
+ val diffToFirstPlaceableOffset =
+ item.offset - firstPlaceableOffset
+ animation.rawOffset = targetFirstPlaceableOffset + diffToFirstPlaceableOffset
+ }
}
}
private fun startAnimationsIfNeeded(item: LazyStaggeredGridMeasuredItem) {
- item.forEachNode { node ->
- val newTarget = item.offset
- val currentTarget = node.rawOffset
- if (currentTarget != LazyLayoutAnimateItemModifierNode.NotInitialized &&
- currentTarget != newTarget
- ) {
- node.animatePlacementDelta(newTarget - currentTarget)
+ val itemInfo = keyToItemInfoMap.getValue(item.key)
+ itemInfo.animations.forEach { animation ->
+ if (animation != null) {
+ val newTarget = item.offset
+ val currentTarget = animation.rawOffset
+ if (currentTarget != LazyLayoutAnimation.NotInitialized &&
+ currentTarget != newTarget
+ ) {
+ animation.animatePlacementDelta(newTarget - currentTarget)
+ }
+ animation.rawOffset = newTarget
}
- node.rawOffset = newTarget
}
}
- private val Any?.node get() = this as? LazyLayoutAnimateItemModifierNode
+ fun getAnimation(key: Any, placeableIndex: Int): LazyLayoutAnimation? =
+ keyToItemInfoMap[key]?.animations?.get(placeableIndex)
private val LazyStaggeredGridMeasuredItem.hasAnimations: Boolean
get() {
- forEachNode { return true }
+ repeat(placeablesCount) { index ->
+ getParentData(index).specs?.let {
+ // found at least one
+ return true
+ }
+ }
return false
}
-
- private inline fun LazyStaggeredGridMeasuredItem.forEachNode(
- block: (LazyLayoutAnimateItemModifierNode) -> Unit
- ) {
- repeat(placeablesCount) { index ->
- getParentData(index).node?.let(block)
- }
- }
}
private class ItemInfo(
var lane: Int,
var span: Int,
var crossAxisOffset: Int
-)
+) {
+ /**
+ * This array will have the same amount of elements as there are placeables on the item.
+ * If the element is not null this means there are specs associated with the given placeable.
+ */
+ var animations = EmptyArray
+ private set
+
+ fun updateAnimation(
+ positionedItem: LazyStaggeredGridMeasuredItem,
+ coroutineScope: CoroutineScope
+ ) {
+ for (i in positionedItem.placeablesCount until animations.size) {
+ animations[i]?.stopAnimations()
+ }
+ if (animations.size != positionedItem.placeablesCount) {
+ animations = animations.copyOf(positionedItem.placeablesCount)
+ }
+ repeat(positionedItem.placeablesCount) { index ->
+ val specs = positionedItem.getParentData(index).specs
+ if (specs == null) {
+ animations[index]?.stopAnimations()
+ animations[index] = null
+ } else {
+ val item = animations[index] ?: LazyLayoutAnimation(coroutineScope).also {
+ animations[index] = it
+ }
+ item.appearanceSpec = specs.appearanceSpec
+ item.placementSpec = specs.placementSpec
+ }
+ }
+ }
+}
+
+private val Any?.specs get() = this as? LazyLayoutAnimationSpecsNode
+
+private val EmptyArray = emptyArray<LazyLayoutAnimation?>()
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemScope.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemScope.kt
index 1ff041d..6f35395 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemScope.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridItemScope.kt
@@ -21,14 +21,11 @@
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring
import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
+import androidx.compose.foundation.lazy.layout.LazyLayoutAnimationSpecsNode
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
-import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ModifierNodeElement
-import androidx.compose.ui.node.ParentDataModifierNode
import androidx.compose.ui.platform.InspectorInfo
-import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntOffset
/**
@@ -62,40 +59,22 @@
internal object LazyStaggeredGridItemScopeImpl : LazyStaggeredGridItemScope {
@ExperimentalFoundationApi
override fun Modifier.animateItemPlacement(animationSpec: FiniteAnimationSpec<IntOffset>) =
- this then AnimateItemPlacementElement(animationSpec)
+ this then AnimateItemElement(animationSpec)
}
-private class AnimateItemPlacementElement(
- val animationSpec: FiniteAnimationSpec<IntOffset>
-) : ModifierNodeElement<AnimateItemPlacementNode>() {
+private data class AnimateItemElement(
+ val placementSpec: FiniteAnimationSpec<IntOffset>
+) : ModifierNodeElement<LazyLayoutAnimationSpecsNode>() {
- override fun create(): AnimateItemPlacementNode = AnimateItemPlacementNode(animationSpec)
+ override fun create(): LazyLayoutAnimationSpecsNode =
+ LazyLayoutAnimationSpecsNode(null, placementSpec)
- override fun update(node: AnimateItemPlacementNode) {
- node.delegatingNode.placementSpec = animationSpec
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (other !is AnimateItemPlacementElement) return false
- return animationSpec != other.animationSpec
- }
-
- override fun hashCode(): Int {
- return animationSpec.hashCode()
+ override fun update(node: LazyLayoutAnimationSpecsNode) {
+ node.placementSpec = placementSpec
}
override fun InspectorInfo.inspectableProperties() {
name = "animateItemPlacement"
- value = animationSpec
+ value = placementSpec
}
}
-
-private class AnimateItemPlacementNode(
- animationSpec: FiniteAnimationSpec<IntOffset>
-) : DelegatingNode(), ParentDataModifierNode {
-
- val delegatingNode = delegate(LazyLayoutAnimateItemModifierNode(null, animationSpec))
-
- override fun Density.modifyParentData(parentData: Any?): Any = delegatingNode
-}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasure.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasure.kt
index d1b13f3..5765b23 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasure.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasure.kt
@@ -18,7 +18,6 @@
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.fastMaxOfOrNull
-import androidx.compose.foundation.lazy.layout.LazyLayoutAnimateItemModifierNode
import androidx.compose.foundation.lazy.layout.LazyLayoutKeyIndexMap
import androidx.compose.foundation.lazy.layout.LazyLayoutMeasureScope
import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridLaneInfo.Companion.FullSpan
@@ -39,6 +38,7 @@
import kotlin.math.min
import kotlin.math.roundToInt
import kotlin.math.sign
+import kotlinx.coroutines.CoroutineScope
private const val DebugLoggingEnabled = false
@@ -88,6 +88,7 @@
mainAxisSpacing: Int,
beforeContentPadding: Int,
afterContentPadding: Int,
+ coroutineScope: CoroutineScope,
): LazyStaggeredGridMeasureResult {
val context = LazyStaggeredGridMeasureContext(
state = state,
@@ -103,6 +104,7 @@
reverseLayout = reverseLayout,
mainAxisSpacing = mainAxisSpacing,
measureScope = this,
+ coroutineScope = coroutineScope
)
val initialItemIndices: IntArray
@@ -185,6 +187,7 @@
val afterContentPadding: Int,
val reverseLayout: Boolean,
val mainAxisSpacing: Int,
+ val coroutineScope: CoroutineScope
) {
val measuredItemProvider = object : LazyStaggeredGridMeasureProvider(
isVertical = isVertical,
@@ -209,7 +212,8 @@
span = span,
beforeContentPadding = beforeContentPadding,
afterContentPadding = afterContentPadding,
- contentType = contentType
+ contentType = contentType,
+ animator = state.placementAnimator
)
}
@@ -802,7 +806,8 @@
positionedItems = positionedItems,
itemProvider = measuredItemProvider,
isVertical = isVertical,
- laneCount = laneCount
+ laneCount = laneCount,
+ coroutineScope = coroutineScope
)
// end placement
@@ -1062,7 +1067,8 @@
val span: Int,
private val beforeContentPadding: Int,
private val afterContentPadding: Int,
- override val contentType: Any?
+ override val contentType: Any?,
+ private val animator: LazyStaggeredGridItemPlacementAnimator
) : LazyStaggeredGridItemInfo {
var isVisible = true
@@ -1120,14 +1126,14 @@
val maxOffset = maxMainAxisOffset
var offset = offset
- val animateNode = getParentData(index) as? LazyLayoutAnimateItemModifierNode
- if (animateNode != null) {
- val animatedOffset = offset + animateNode.placementDelta
+ val animation = animator.getAnimation(key, index)
+ if (animation != null) {
+ val animatedOffset = offset + animation.placementDelta
// cancel the animation if current and target offsets are both out of the bounds.
if ((offset.mainAxis <= minOffset && animatedOffset.mainAxis <= minOffset) ||
(offset.mainAxis >= maxOffset && animatedOffset.mainAxis >= maxOffset)
) {
- animateNode.cancelPlacementAnimation()
+ animation.cancelPlacementAnimation()
}
offset = animatedOffset
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasurePolicy.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasurePolicy.kt
index 2ba719b93..c0ece02 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasurePolicy.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/staggeredgrid/LazyStaggeredGridMeasurePolicy.kt
@@ -33,6 +33,7 @@
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.constrainHeight
import androidx.compose.ui.unit.constrainWidth
+import kotlinx.coroutines.CoroutineScope
@OptIn(ExperimentalFoundationApi::class)
@Composable
@@ -44,6 +45,7 @@
orientation: Orientation,
mainAxisSpacing: Dp,
crossAxisSpacing: Dp,
+ coroutineScope: CoroutineScope,
slots: Density.(Constraints) -> LazyStaggeredGridSlots
): LazyLayoutMeasureScope.(Constraints) -> LazyStaggeredGridMeasureResult = remember(
state,
@@ -116,6 +118,7 @@
reverseLayout = reverseLayout,
beforeContentPadding = beforeContentPadding,
afterContentPadding = afterContentPadding,
+ coroutineScope = coroutineScope
).also {
state.applyMeasureResult(it)
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
index ec5478c..f7776ef 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyboardOptions.kt
@@ -22,6 +22,7 @@
import androidx.compose.ui.text.input.ImeOptions
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.text.input.PlatformImeOptions
/**
* The keyboard configuration options for TextFields. It is not guaranteed if software keyboard
@@ -42,13 +43,15 @@
* icons on the keyboard. For example, search icon may be shown if [ImeAction.Search] is specified.
* When [ImeOptions.singleLine] is false, the keyboard might show return key rather than the action
* requested here.
+ * @param platformImeOptions defines the platform specific IME options.
*/
@Immutable
class KeyboardOptions constructor(
val capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
val autoCorrect: Boolean = true,
val keyboardType: KeyboardType = KeyboardType.Text,
- val imeAction: ImeAction = ImeAction.Default
+ val imeAction: ImeAction = ImeAction.Default,
+ val platformImeOptions: PlatformImeOptions? = null
) {
companion object {
/**
@@ -58,6 +61,23 @@
val Default = KeyboardOptions()
}
+ @Deprecated(
+ "Please use the new constructor that takes optional platformImeOptions parameter.",
+ level = DeprecationLevel.HIDDEN
+ )
+ constructor(
+ capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
+ autoCorrect: Boolean = true,
+ keyboardType: KeyboardType = KeyboardType.Text,
+ imeAction: ImeAction = ImeAction.Default
+ ) : this(
+ capitalization = capitalization,
+ autoCorrect = autoCorrect,
+ keyboardType = keyboardType,
+ imeAction = imeAction,
+ platformImeOptions = null
+ )
+
/**
* Returns a new [ImeOptions] with the values that are in this [KeyboardOptions] and provided
* params.
@@ -69,20 +89,42 @@
capitalization = capitalization,
autoCorrect = autoCorrect,
keyboardType = keyboardType,
- imeAction = imeAction
+ imeAction = imeAction,
+ platformImeOptions = platformImeOptions
)
fun copy(
capitalization: KeyboardCapitalization = this.capitalization,
autoCorrect: Boolean = this.autoCorrect,
keyboardType: KeyboardType = this.keyboardType,
+ imeAction: ImeAction = this.imeAction,
+ platformImeOptions: PlatformImeOptions? = this.platformImeOptions
+ ): KeyboardOptions {
+ return KeyboardOptions(
+ capitalization = capitalization,
+ autoCorrect = autoCorrect,
+ keyboardType = keyboardType,
+ imeAction = imeAction,
+ platformImeOptions = platformImeOptions
+ )
+ }
+
+ @Deprecated(
+ "Please use the new copy function that takes optional platformImeOptions parameter.",
+ level = DeprecationLevel.HIDDEN
+ )
+ fun copy(
+ capitalization: KeyboardCapitalization = this.capitalization,
+ autoCorrect: Boolean = this.autoCorrect,
+ keyboardType: KeyboardType = this.keyboardType,
imeAction: ImeAction = this.imeAction
): KeyboardOptions {
return KeyboardOptions(
capitalization = capitalization,
autoCorrect = autoCorrect,
keyboardType = keyboardType,
- imeAction = imeAction
+ imeAction = imeAction,
+ platformImeOptions = this.platformImeOptions
)
}
@@ -94,6 +136,7 @@
if (autoCorrect != other.autoCorrect) return false
if (keyboardType != other.keyboardType) return false
if (imeAction != other.imeAction) return false
+ if (platformImeOptions != other.platformImeOptions) return false
return true
}
@@ -103,11 +146,13 @@
result = 31 * result + autoCorrect.hashCode()
result = 31 * result + keyboardType.hashCode()
result = 31 * result + imeAction.hashCode()
+ result = 31 * result + platformImeOptions.hashCode()
return result
}
override fun toString(): String {
return "KeyboardOptions(capitalization=$capitalization, autoCorrect=$autoCorrect, " +
- "keyboardType=$keyboardType, imeAction=$imeAction)"
+ "keyboardType=$keyboardType, imeAction=$imeAction, " +
+ "platformImeOptions=$platformImeOptions)"
}
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
index 3e58a9e..a574637 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/BasicTextField2.kt
@@ -32,7 +32,6 @@
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.heightInLines
-import androidx.compose.foundation.text.selection.SelectionHandle
import androidx.compose.foundation.text.selection.SelectionHandleAnchor
import androidx.compose.foundation.text.selection.SelectionHandleInfo
import androidx.compose.foundation.text.selection.SelectionHandleInfoKey
@@ -47,6 +46,7 @@
import androidx.compose.foundation.text2.input.internal.TextFieldDecoratorModifier
import androidx.compose.foundation.text2.input.internal.TextFieldTextLayoutModifier
import androidx.compose.foundation.text2.input.internal.TextLayoutState
+import androidx.compose.foundation.text2.selection.TextFieldSelectionHandle2
import androidx.compose.foundation.text2.selection.TextFieldSelectionState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -302,29 +302,27 @@
) {
val startHandleState = selectionState.startSelectionHandle
if (startHandleState.visible) {
- SelectionHandle(
- position = startHandleState.position,
+ TextFieldSelectionHandle2(
+ positionProvider = { selectionState.startSelectionHandle.position },
isStartHandle = true,
direction = startHandleState.direction,
handlesCrossed = startHandleState.handlesCrossed,
modifier = Modifier.pointerInput(selectionState) {
with(selectionState) { selectionHandleGestures(true) }
- },
- content = null
+ }
)
}
val endHandleState = selectionState.endSelectionHandle
if (endHandleState.visible) {
- SelectionHandle(
- position = endHandleState.position,
+ TextFieldSelectionHandle2(
+ positionProvider = { selectionState.endSelectionHandle.position },
isStartHandle = false,
direction = endHandleState.direction,
handlesCrossed = endHandleState.handlesCrossed,
modifier = Modifier.pointerInput(selectionState) {
with(selectionState) { selectionHandleGestures(false) }
- },
- content = null
+ }
)
}
}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.kt
new file mode 100644
index 0000000..1273aae
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.selection
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.text.style.ResolvedTextDirection
+
+@Composable
+internal expect fun TextFieldSelectionHandle2(
+ positionProvider: OffsetProvider,
+ isStartHandle: Boolean,
+ direction: ResolvedTextDirection,
+ handlesCrossed: Boolean,
+ modifier: Modifier
+)
+
+/**
+ * Avoids boxing of [Offset] which is an inline value class.
+ */
+internal fun interface OffsetProvider {
+ fun provide(): Offset
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt
index c12257d..9f4b7f1 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionState.kt
@@ -35,6 +35,7 @@
import androidx.compose.foundation.text2.input.TextFieldState
import androidx.compose.foundation.text2.input.getSelectedText
import androidx.compose.foundation.text2.input.internal.TextLayoutState
+import androidx.compose.foundation.text2.input.internal.coerceIn
import androidx.compose.foundation.text2.input.selectAll
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
@@ -726,7 +727,19 @@
val directionOffset = if (isStartHandle) selection.start else max(selection.end - 1, 0)
val direction = layoutResult.getBidiRunDirection(directionOffset)
val handlesCrossed = selection.reversed
- return TextFieldHandleState(true, position, direction, handlesCrossed)
+
+ // Handle normally is visible when it's out of bounds but when the handle is being dragged,
+ // we let it stay on the screen to maintain gesture continuation. However, we still want
+ // to coerce handle's position to visible bounds to not let it jitter while scrolling the
+ // TextField as the selection is expanding.
+ val coercedPosition = innerCoordinates?.visibleBounds()?.let { position.coerceIn(it) }
+ ?: position
+ return TextFieldHandleState(
+ visible = true,
+ position = coercedPosition,
+ direction = direction,
+ handlesCrossed = handlesCrossed
+ )
}
private fun getHandlePosition(isStartHandle: Boolean): Offset {
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.desktop.kt
new file mode 100644
index 0000000..8ac7119
--- /dev/null
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text2/selection/TextFieldSelectionHandles.desktop.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.foundation.text2.selection
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.ResolvedTextDirection
+
+/**
+ * Handles are not supported on Desktop.
+ */
+@Composable
+internal actual fun TextFieldSelectionHandle2(
+ positionProvider: OffsetProvider,
+ isStartHandle: Boolean,
+ direction: ResolvedTextDirection,
+ handlesCrossed: Boolean,
+ modifier: Modifier
+) {}
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt
index 33ba64e..766c37e 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/text/KeyboardOptionsTest.kt
@@ -16,6 +16,7 @@
package androidx.compose.foundation.text
+import androidx.compose.ui.text.input.AndroidImeOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.ImeOptions
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -30,11 +31,14 @@
@Test
fun test_toImeOption() {
+ val platformImeOptions = AndroidImeOptions("privateImeOptions")
+
val keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Go,
capitalization = KeyboardCapitalization.Sentences,
- autoCorrect = false
+ autoCorrect = false,
+ platformImeOptions = platformImeOptions
)
assertThat(keyboardOptions.toImeOptions(singleLine = true)).isEqualTo(
@@ -43,7 +47,8 @@
imeAction = ImeAction.Go,
capitalization = KeyboardCapitalization.Sentences,
autoCorrect = false,
- singleLine = true
+ singleLine = true,
+ platformImeOptions = platformImeOptions
)
)
}
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialPerfettoSdkBenchmark.kt
similarity index 97%
rename from compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialPerfettoSdkBenchmark.kt
index 3115e6b..002886f 100644
--- a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialTracingBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialPerfettoSdkBenchmark.kt
@@ -41,7 +41,7 @@
*/
@OptIn(ExperimentalMetricApi::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R) // TODO(234351579): Support API < 30
-class TrivialTracingBenchmark(private val composableName: String) {
+class TrivialPerfettoSdkBenchmark(private val composableName: String) {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
similarity index 73%
rename from compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt
rename to compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
index 47cbb44..eb9ab43 100644
--- a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupTracingBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkBenchmark.kt
@@ -26,7 +26,6 @@
import androidx.testutils.measureStartup
import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.MatcherAssert.assertThat
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,26 +34,23 @@
@OptIn(ExperimentalMetricApi::class)
@LargeTest
@RunWith(Parameterized::class)
-class TrivialStartupTracingBenchmark(
+class TrivialStartupPerfettoSdkBenchmark(
private val startupMode: StartupMode,
private val compilationMode: CompilationMode,
- private val isFullTracingEnabled: Boolean
+ private val isPerfettoSdkEnabled: Boolean
) {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
- // TODO(283953019): enable alongside StartupTracingInitializer (pending performance testing)
- @Ignore
@Test
fun startup() = try {
- Arguments.fullTracingEnableOverride = isFullTracingEnabled
- assertThat(Arguments.fullTracingEnable, `is`(isFullTracingEnabled))
+ Arguments.perfettoSdkTracingEnableOverride = isPerfettoSdkEnabled
+ assertThat(Arguments.perfettoSdkTracingEnable, `is`(isPerfettoSdkEnabled))
try {
val perfettoSdkTraceSection = TraceSectionMetric(
- "androidx.compose.integration.macrobenchmark.target." +
- "TrivialStartupTracingActivity.onCreate.<anonymous>" +
- " (TrivialStartupTracingActivity.kt:33)"
+ "%TrivialStartupTracingActivity.onCreate%" +
+ " (TrivialStartupTracingActivity.kt:%)"
)
benchmarkRule.measureStartup(
compilationMode = compilationMode,
@@ -67,25 +63,28 @@
"TRIVIAL_STARTUP_TRACING_ACTIVITY"
}
} catch (e: IllegalArgumentException) {
- if (!isFullTracingEnabled &&
+ if (!isPerfettoSdkEnabled &&
e.message?.contains("Unable to read any metrics during benchmark") == true
) {
- // this is expected, we don't expect Perfetto SDK Tracing section present
- // when full tracing is disabled
+ // We are relying on the fact that Macrobenchmark will throw an exception when it
+ // cannot find any metrics, and given we are looking for one specific metric
+ // (a Composable function emitted by Compose Tracing), we are able to tell if
+ // Compose Tracing is working (enabled) or not, both of which we want to verify in
+ // this test.
} else throw e // this is a legitimate failure
}
} finally {
- Arguments.fullTracingEnableOverride = null
+ Arguments.perfettoSdkTracingEnableOverride = null
}
companion object {
- @Parameterized.Parameters(name = "startup={0},compilation={1},fullTracing={2}")
+ @Parameterized.Parameters(name = "startup={0},compilation={1},perfettoSdk={2}")
@JvmStatic
fun parameters() = listOf(
- arrayOf(StartupMode.COLD, CompilationMode.DEFAULT, /* fullTracing = */ true),
- arrayOf(StartupMode.COLD, CompilationMode.DEFAULT, /* fullTracing = */ false),
- arrayOf(StartupMode.WARM, CompilationMode.DEFAULT, /* fullTracing = */ true),
- arrayOf(StartupMode.WARM, CompilationMode.DEFAULT, /* fullTracing = */ false),
+ arrayOf(StartupMode.COLD, CompilationMode.DEFAULT, /* perfettoSdk = */ true),
+ arrayOf(StartupMode.COLD, CompilationMode.DEFAULT, /* perfettoSdk = */ false),
+ arrayOf(StartupMode.WARM, CompilationMode.DEFAULT, /* perfettoSdk = */ true),
+ arrayOf(StartupMode.WARM, CompilationMode.DEFAULT, /* perfettoSdk = */ false),
)
}
}
diff --git a/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkOverheadBenchmark.kt b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkOverheadBenchmark.kt
new file mode 100644
index 0000000..28a6c97
--- /dev/null
+++ b/compose/integration-tests/macrobenchmark/src/main/java/androidx/compose/integration/macrobenchmark/TrivialStartupPerfettoSdkOverheadBenchmark.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.integration.macrobenchmark
+
+import androidx.benchmark.Arguments
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.filters.LargeTest
+import androidx.testutils.createStartupCompilationParams
+import androidx.testutils.measureStartup
+import org.hamcrest.CoreMatchers.`is`
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@LargeTest
+@RunWith(Parameterized::class)
+class TrivialStartupPerfettoSdkOverheadBenchmark(
+ private val startupMode: StartupMode,
+ private val compilationMode: CompilationMode,
+ private val isPerfettoSdkEnabled: Boolean
+) {
+ @get:Rule
+ val benchmarkRule = MacrobenchmarkRule()
+
+ @Test
+ fun startup() = try {
+ Arguments.perfettoSdkTracingEnableOverride = isPerfettoSdkEnabled
+ assertThat(Arguments.perfettoSdkTracingEnable, `is`(isPerfettoSdkEnabled))
+
+ benchmarkRule.measureStartup(
+ compilationMode = compilationMode,
+ startupMode = startupMode,
+ packageName = "androidx.compose.integration.macrobenchmark.target"
+ ) {
+ action = "androidx.compose.integration.macrobenchmark.target." +
+ "TRIVIAL_STARTUP_TRACING_ACTIVITY"
+ }
+ } finally {
+ Arguments.perfettoSdkTracingEnableOverride = null
+ }
+
+ companion object {
+ // intended for local testing of all possible configurations
+ private const val exhaustiveMode = false
+
+ @Parameterized.Parameters(name = "startup={0},compilation={1},perfettoSdk={2}")
+ @JvmStatic
+ fun parameters() =
+ when {
+ exhaustiveMode ->
+ // complete set for testing locally
+ createStartupCompilationParams()
+ .flatMap { listOf(it + true, it + false) } /* perfetto sdk enabled */
+ else ->
+ // subset for testing in CI:
+ // compilation isn't expected to affect this, so we just look at startup time
+ // for cold and not, since the behavior is very different in those scenarios
+ createStartupCompilationParams(
+ listOf(StartupMode.COLD, StartupMode.WARM),
+ listOf(CompilationMode.DEFAULT)
+ ).map { it + true } /* perfetto sdk enabled */
+ }
+ }
+}
diff --git a/compose/material/material/api/current.txt b/compose/material/material/api/current.txt
index aa36fd8..d319950 100644
--- a/compose/material/material/api/current.txt
+++ b/compose/material/material/api/current.txt
@@ -14,17 +14,24 @@
public final class AppBarDefaults {
method public float getBottomAppBarElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getBottomAppBarWindowInsets();
method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
method public float getTopAppBarElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getTopAppBarWindowInsets();
property public final float BottomAppBarElevation;
property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
property public final float TopAppBarElevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets bottomAppBarWindowInsets;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets topAppBarWindowInsets;
field public static final androidx.compose.material.AppBarDefaults INSTANCE;
}
public final class AppBarKt {
+ method @androidx.compose.runtime.Composable public static void BottomAppBar(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.ui.graphics.Shape? cutoutShape, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.ui.graphics.Shape? cutoutShape, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void TopAppBar(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void TopAppBar(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional long backgroundColor, optional long contentColor, optional float elevation);
method @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional long backgroundColor, optional long contentColor, optional float elevation);
}
@@ -113,11 +120,14 @@
public final class BottomNavigationDefaults {
method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
field public static final androidx.compose.material.BottomNavigationDefaults INSTANCE;
}
public final class BottomNavigationKt {
+ method @androidx.compose.runtime.Composable public static void BottomNavigation(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void BottomNavigation(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void BottomNavigationItem(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
}
@@ -578,11 +588,14 @@
public final class NavigationRailDefaults {
method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
field public static final androidx.compose.material.NavigationRailDefaults INSTANCE;
}
public final class NavigationRailKt {
+ method @androidx.compose.runtime.Composable public static void NavigationRail(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void NavigationRail(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void NavigationRailItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
}
@@ -638,7 +651,14 @@
property @Deprecated public final float factorAtMin;
}
+ public final class ScaffoldDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getContentWindowInsets();
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets contentWindowInsets;
+ field public static final androidx.compose.material.ScaffoldDefaults INSTANCE;
+ }
+
public final class ScaffoldKt {
+ method @androidx.compose.runtime.Composable public static void Scaffold(androidx.compose.foundation.layout.WindowInsets contentWindowInsets, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/api/restricted_current.txt b/compose/material/material/api/restricted_current.txt
index aa36fd8..d319950 100644
--- a/compose/material/material/api/restricted_current.txt
+++ b/compose/material/material/api/restricted_current.txt
@@ -14,17 +14,24 @@
public final class AppBarDefaults {
method public float getBottomAppBarElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getBottomAppBarWindowInsets();
method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
method public float getTopAppBarElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getTopAppBarWindowInsets();
property public final float BottomAppBarElevation;
property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
property public final float TopAppBarElevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets bottomAppBarWindowInsets;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets topAppBarWindowInsets;
field public static final androidx.compose.material.AppBarDefaults INSTANCE;
}
public final class AppBarKt {
+ method @androidx.compose.runtime.Composable public static void BottomAppBar(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.ui.graphics.Shape? cutoutShape, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void BottomAppBar(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional androidx.compose.ui.graphics.Shape? cutoutShape, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void TopAppBar(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void TopAppBar(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional androidx.compose.foundation.layout.PaddingValues contentPadding, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional long backgroundColor, optional long contentColor, optional float elevation);
method @androidx.compose.runtime.Composable public static void TopAppBar(kotlin.jvm.functions.Function0<kotlin.Unit> title, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function0<kotlin.Unit>? navigationIcon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> actions, optional long backgroundColor, optional long contentColor, optional float elevation);
}
@@ -113,11 +120,14 @@
public final class BottomNavigationDefaults {
method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
field public static final androidx.compose.material.BottomNavigationDefaults INSTANCE;
}
public final class BottomNavigationKt {
+ method @androidx.compose.runtime.Composable public static void BottomNavigation(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void BottomNavigation(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void BottomNavigationItem(androidx.compose.foundation.layout.RowScope, boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
}
@@ -578,11 +588,14 @@
public final class NavigationRailDefaults {
method public float getElevation();
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getWindowInsets();
property public final float Elevation;
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets windowInsets;
field public static final androidx.compose.material.NavigationRailDefaults INSTANCE;
}
public final class NavigationRailKt {
+ method @androidx.compose.runtime.Composable public static void NavigationRail(androidx.compose.foundation.layout.WindowInsets windowInsets, optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void NavigationRail(optional androidx.compose.ui.Modifier modifier, optional long backgroundColor, optional long contentColor, optional float elevation, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? header, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void NavigationRailItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional long selectedContentColor, optional long unselectedContentColor);
}
@@ -638,7 +651,14 @@
property @Deprecated public final float factorAtMin;
}
+ public final class ScaffoldDefaults {
+ method @androidx.compose.runtime.Composable public androidx.compose.foundation.layout.WindowInsets getContentWindowInsets();
+ property @androidx.compose.runtime.Composable public final androidx.compose.foundation.layout.WindowInsets contentWindowInsets;
+ field public static final androidx.compose.material.ScaffoldDefaults INSTANCE;
+ }
+
public final class ScaffoldKt {
+ method @androidx.compose.runtime.Composable public static void Scaffold(androidx.compose.foundation.layout.WindowInsets contentWindowInsets, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static void Scaffold(optional androidx.compose.ui.Modifier modifier, optional androidx.compose.material.ScaffoldState scaffoldState, optional kotlin.jvm.functions.Function0<kotlin.Unit> topBar, optional kotlin.jvm.functions.Function0<kotlin.Unit> bottomBar, optional kotlin.jvm.functions.Function1<? super androidx.compose.material.SnackbarHostState,kotlin.Unit> snackbarHost, optional kotlin.jvm.functions.Function0<kotlin.Unit> floatingActionButton, optional int floatingActionButtonPosition, optional boolean isFloatingActionButtonDocked, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? drawerContent, optional boolean drawerGesturesEnabled, optional androidx.compose.ui.graphics.Shape drawerShape, optional float drawerElevation, optional long drawerBackgroundColor, optional long drawerContentColor, optional long drawerScrimColor, optional long backgroundColor, optional long contentColor, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.PaddingValues,kotlin.Unit> content);
method @androidx.compose.runtime.Composable public static androidx.compose.material.ScaffoldState rememberScaffoldState(optional androidx.compose.material.DrawerState drawerState, optional androidx.compose.material.SnackbarHostState snackbarHostState);
}
diff --git a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogScaffold.kt b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogScaffold.kt
index d86161c..746c712 100644
--- a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogScaffold.kt
+++ b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogScaffold.kt
@@ -21,6 +21,7 @@
import androidx.compose.material.ModalBottomSheetLayout
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.Scaffold
+import androidx.compose.material.ScaffoldDefaults
import androidx.compose.material.catalog.library.model.Theme
import androidx.compose.material.catalog.library.ui.theme.ThemePicker
import androidx.compose.material.catalog.library.util.GuidelinesUrl
@@ -76,6 +77,7 @@
) {
val context = LocalContext.current
Scaffold(
+ contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
topBar = {
CatalogTopAppBar(
title = topBarTitle,
diff --git a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogTopAppBar.kt b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogTopAppBar.kt
index 80688a3..cd707c4 100644
--- a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogTopAppBar.kt
+++ b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/common/CatalogTopAppBar.kt
@@ -18,37 +18,26 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.safeDrawing
-import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.AppBarDefaults
import androidx.compose.material.Divider
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.catalog.library.R
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.MoreVert
-import androidx.compose.material.primarySurface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.unit.dp
@Composable
fun CatalogTopAppBar(
@@ -65,89 +54,78 @@
onLicensesClick: () -> Unit = {}
) {
var moreMenuExpanded by remember { mutableStateOf(false) }
- // Wrapping in a Surface to handle window insets
- // https://issuetracker.google.com/issues/183161866
- Surface(
- color = MaterialTheme.colors.primarySurface,
- elevation = AppBarDefaults.TopAppBarElevation
- ) {
- TopAppBar(
- title = {
- Text(
- text = title,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis
- )
- },
- actions = {
- Box {
- Row {
- IconButton(onClick = onThemeClick) {
- Icon(
- painter = painterResource(id = R.drawable.ic_palette_24dp),
- contentDescription = null
- )
- }
- IconButton(onClick = { moreMenuExpanded = true }) {
- Icon(
- imageVector = Icons.Default.MoreVert,
- contentDescription = null
- )
- }
- }
- MoreMenu(
- expanded = moreMenuExpanded,
- onDismissRequest = { moreMenuExpanded = false },
- onGuidelinesClick = {
- onGuidelinesClick()
- moreMenuExpanded = false
- },
- onDocsClick = {
- onDocsClick()
- moreMenuExpanded = false
- },
- onSourceClick = {
- onSourceClick()
- moreMenuExpanded = false
- },
- onIssueClick = {
- onIssueClick()
- moreMenuExpanded = false
- },
- onTermsClick = {
- onTermsClick()
- moreMenuExpanded = false
- },
- onPrivacyClick = {
- onPrivacyClick()
- moreMenuExpanded = false
- },
- onLicensesClick = {
- onLicensesClick()
- moreMenuExpanded = false
- }
- )
- }
- },
- navigationIcon = if (showBackNavigationIcon) {
- {
- IconButton(onClick = onBackClick) {
+ TopAppBar(
+ windowInsets = AppBarDefaults.topAppBarWindowInsets,
+ title = {
+ Text(
+ text = title,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ },
+ actions = {
+ Box {
+ Row {
+ IconButton(onClick = onThemeClick) {
Icon(
- imageVector = Icons.Default.ArrowBack,
+ painter = painterResource(id = R.drawable.ic_palette_24dp),
+ contentDescription = null
+ )
+ }
+ IconButton(onClick = { moreMenuExpanded = true }) {
+ Icon(
+ imageVector = Icons.Default.MoreVert,
contentDescription = null
)
}
}
- } else {
- null
- },
- backgroundColor = Color.Transparent,
- elevation = 0.dp,
- modifier = Modifier.windowInsetsPadding(
- WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top)
- )
- )
- }
+ MoreMenu(
+ expanded = moreMenuExpanded,
+ onDismissRequest = { moreMenuExpanded = false },
+ onGuidelinesClick = {
+ onGuidelinesClick()
+ moreMenuExpanded = false
+ },
+ onDocsClick = {
+ onDocsClick()
+ moreMenuExpanded = false
+ },
+ onSourceClick = {
+ onSourceClick()
+ moreMenuExpanded = false
+ },
+ onIssueClick = {
+ onIssueClick()
+ moreMenuExpanded = false
+ },
+ onTermsClick = {
+ onTermsClick()
+ moreMenuExpanded = false
+ },
+ onPrivacyClick = {
+ onPrivacyClick()
+ moreMenuExpanded = false
+ },
+ onLicensesClick = {
+ onLicensesClick()
+ moreMenuExpanded = false
+ }
+ )
+ }
+ },
+ navigationIcon = if (showBackNavigationIcon) {
+ {
+ IconButton(onClick = onBackClick) {
+ Icon(
+ imageVector = Icons.Default.ArrowBack,
+ contentDescription = null
+ )
+ }
+ }
+ } else {
+ null
+ }
+ )
}
@Composable
diff --git a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/component/Component.kt b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/component/Component.kt
index d311df8..7180680 100644
--- a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/component/Component.kt
+++ b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/component/Component.kt
@@ -19,14 +19,9 @@
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@@ -68,11 +63,8 @@
) { paddingValues ->
LazyColumn(
modifier = Modifier
- .padding(paddingValues)
.padding(horizontal = ComponentPadding),
- contentPadding = WindowInsets.safeDrawing
- .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
- .asPaddingValues()
+ contentPadding = paddingValues
) {
item {
Box(
diff --git a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/example/Example.kt b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/example/Example.kt
index 31fc61d..156c3a1 100644
--- a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/example/Example.kt
+++ b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/example/Example.kt
@@ -17,13 +17,8 @@
package androidx.compose.material.catalog.library.ui.example
import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
-import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.catalog.library.model.Component
import androidx.compose.material.catalog.library.model.Example
import androidx.compose.material.catalog.library.model.Theme
@@ -53,11 +48,7 @@
Box(
modifier = Modifier
.fillMaxSize()
- .padding(paddingValues)
- .windowInsetsPadding(
- WindowInsets.safeDrawing
- .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
- ),
+ .padding(paddingValues),
contentAlignment = Alignment.Center
) {
example.content()
diff --git a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/home/Home.kt b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/home/Home.kt
index bc17a72..d5c7873 100644
--- a/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/home/Home.kt
+++ b/compose/material/material/integration-tests/material-catalog/src/main/java/androidx/compose/material/catalog/library/ui/home/Home.kt
@@ -17,12 +17,6 @@
package androidx.compose.material.catalog.library.ui.home
import androidx.compose.foundation.layout.BoxWithConstraints
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.asPaddingValues
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.itemsIndexed
@@ -32,7 +26,6 @@
import androidx.compose.material.catalog.library.ui.common.CatalogScaffold
import androidx.compose.material.catalog.library.ui.component.ComponentItem
import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@@ -48,7 +41,7 @@
theme = theme,
onThemeChange = onThemeChange
) { paddingValues ->
- BoxWithConstraints(modifier = Modifier.padding(paddingValues)) {
+ BoxWithConstraints {
val cellsCount = maxOf((maxWidth / HomeCellMinSize).toInt(), 1)
LazyVerticalGrid(
// LazyGridScope doesn't expose nColumns from LazyVerticalGrid
@@ -64,9 +57,7 @@
)
}
},
- contentPadding = WindowInsets.safeDrawing
- .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
- .asPaddingValues()
+ contentPadding = paddingValues
)
}
}
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/AppBarSamples.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/AppBarSamples.kt
index c35fdba..9310d1c 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/AppBarSamples.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/AppBarSamples.kt
@@ -18,6 +18,7 @@
import androidx.annotation.Sampled
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.material.AppBarDefaults
import androidx.compose.material.BottomAppBar
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Icon
@@ -36,6 +37,7 @@
@Composable
fun SimpleTopAppBar() {
TopAppBar(
+ windowInsets = AppBarDefaults.topAppBarWindowInsets,
title = { Text("Simple TopAppBar") },
navigationIcon = {
IconButton(onClick = { /* doSomething() */ }) {
@@ -57,7 +59,7 @@
@Sampled
@Composable
fun SimpleBottomAppBar() {
- BottomAppBar {
+ BottomAppBar(windowInsets = AppBarDefaults.bottomAppBarWindowInsets) {
// Leading icons should typically have a high content alpha
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
IconButton(onClick = { /* doSomething() */ }) {
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BottomNavigationSamples.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BottomNavigationSamples.kt
index e35ccac..55ace32 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BottomNavigationSamples.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BottomNavigationSamples.kt
@@ -18,6 +18,7 @@
import androidx.annotation.Sampled
import androidx.compose.material.BottomNavigation
+import androidx.compose.material.BottomNavigationDefaults
import androidx.compose.material.BottomNavigationItem
import androidx.compose.material.Icon
import androidx.compose.material.Text
@@ -35,7 +36,7 @@
var selectedItem by remember { mutableStateOf(0) }
val items = listOf("Songs", "Artists", "Playlists")
- BottomNavigation {
+ BottomNavigation(windowInsets = BottomNavigationDefaults.windowInsets) {
items.forEachIndexed { index, item ->
BottomNavigationItem(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/NavigationRailSample.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/NavigationRailSample.kt
index 0abeb52..01b7d24 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/NavigationRailSample.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/NavigationRailSample.kt
@@ -20,6 +20,7 @@
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material.Icon
import androidx.compose.material.NavigationRail
+import androidx.compose.material.NavigationRailDefaults
import androidx.compose.material.NavigationRailItem
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
@@ -39,7 +40,7 @@
var selectedItem by remember { mutableStateOf(0) }
val items = listOf("Home", "Search", "Settings")
val icons = listOf(Icons.Filled.Home, Icons.Filled.Search, Icons.Filled.Settings)
- NavigationRail {
+ NavigationRail(windowInsets = NavigationRailDefaults.windowInsets) {
items.forEachIndexed { index, item ->
NavigationRailItem(
icon = { Icon(icons[index], contentDescription = item) },
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/ScaffoldSamples.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/ScaffoldSamples.kt
index f399b4a..4198525 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/ScaffoldSamples.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/ScaffoldSamples.kt
@@ -38,6 +38,7 @@
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
+import androidx.compose.material.ScaffoldDefaults
import androidx.compose.material.Snackbar
import androidx.compose.material.SnackbarHost
import androidx.compose.material.SnackbarHostState
@@ -101,6 +102,7 @@
onClick = { /* fab click handler */ }
)
},
+ contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
content = { innerPadding ->
LazyColumn(contentPadding = innerPadding) {
items(count = 100) {
@@ -174,6 +176,7 @@
shape = fabShape
)
},
+ contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
floatingActionButtonPosition = FabPosition.Center,
isFloatingActionButtonDocked = true,
content = { innerPadding ->
@@ -210,6 +213,7 @@
}
)
},
+ contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
content = { innerPadding ->
Text(
text = "Body content",
@@ -247,6 +251,7 @@
}
)
},
+ contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
content = { innerPadding ->
Text(
text = "Custom Snackbar Demo",
@@ -293,6 +298,7 @@
}
)
},
+ contentWindowInsets = ScaffoldDefaults.contentWindowInsets,
content = { innerPadding ->
Text(
"Snackbar demo",
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/AppBarTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/AppBarTest.kt
index 4c44037d..7eb23a7 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/AppBarTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/AppBarTest.kt
@@ -17,6 +17,7 @@
package androidx.compose.material
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@@ -119,6 +120,59 @@
}
@Test
+ fun topAppBar_default_positioning_respectsWindowInsets() {
+ val fakeInset = 10.dp
+ rule.setMaterialContent {
+ Box(Modifier.testTag("bar")) {
+ TopAppBar(
+ windowInsets = WindowInsets(fakeInset, fakeInset, fakeInset, fakeInset),
+ navigationIcon = {
+ FakeIcon(Modifier.testTag("navigationIcon"))
+ },
+ title = {
+ Text("title", Modifier.testTag("title"))
+ },
+ actions = {
+ FakeIcon(Modifier.testTag("action"))
+ }
+ )
+ }
+ }
+
+ val appBarBounds = rule.onNodeWithTag("bar").getUnclippedBoundsInRoot()
+ val titleBounds = rule.onNodeWithTag("title").getUnclippedBoundsInRoot()
+ val appBarBottomEdgeY = appBarBounds.top + appBarBounds.height
+
+ rule.onNodeWithTag("navigationIcon")
+ // Navigation icon should be 4.dp from the start
+ .assertLeftPositionInRootIsEqualTo(AppBarStartAndEndPadding + fakeInset)
+ // Navigation icon should be 4.dp from the bottom
+ .assertTopPositionInRootIsEqualTo(
+ appBarBottomEdgeY - AppBarStartAndEndPadding - FakeIconSize - fakeInset
+ )
+
+ rule.onNodeWithTag("title")
+ // Title should be 72.dp from the start
+ // 4.dp padding for the whole app bar + 68.dp inset
+ .assertLeftPositionInRootIsEqualTo(4.dp + 68.dp + fakeInset)
+ // Title should be vertically centered
+ .assertTopPositionInRootIsEqualTo(
+ // no need to check for fake insets since we check the center-ness
+ (appBarBounds.height - titleBounds.height) / 2
+ )
+
+ rule.onNodeWithTag("action")
+ // Action should be placed at the end
+ .assertLeftPositionInRootIsEqualTo(
+ expectedActionPosition(appBarBounds.width) - fakeInset
+ )
+ // Action should be 4.dp from the bottom
+ .assertTopPositionInRootIsEqualTo(
+ appBarBottomEdgeY - AppBarStartAndEndPadding - FakeIconSize - fakeInset
+ )
+ }
+
+ @Test
fun topAppBar_noNavigationIcon_positioning() {
rule.setMaterialContent {
Box(Modifier.testTag("bar")) {
@@ -242,6 +296,30 @@
}
@Test
+ fun bottomAppBar_default_positioning_respectsWindowInsets() {
+ val fakeInsets = 8.dp
+ rule.setMaterialContent {
+ BottomAppBar(
+ WindowInsets(fakeInsets, fakeInsets, fakeInsets, fakeInsets),
+ Modifier.testTag("bar")
+ ) {
+ FakeIcon(Modifier.testTag("icon"))
+ }
+ }
+
+ val appBarBounds = rule.onNodeWithTag("bar").getUnclippedBoundsInRoot()
+ val appBarBottomEdgeY = appBarBounds.top + appBarBounds.height
+
+ rule.onNodeWithTag("icon")
+ // Child icon should be 4.dp from the start
+ .assertLeftPositionInRootIsEqualTo(AppBarStartAndEndPadding + fakeInsets)
+ // Child icon should be 4.dp from the bottom
+ .assertTopPositionInRootIsEqualTo(
+ appBarBottomEdgeY - AppBarStartAndEndPadding - FakeIconSize - fakeInsets
+ )
+ }
+
+ @Test
fun bottomAppBar_contentAlpha() {
var alpha: Float? = null
var medium: Float? = null
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationTest.kt
index 64a43ff..008addd 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BottomNavigationTest.kt
@@ -16,9 +16,14 @@
package androidx.compose.material
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.samples.BottomNavigationSample
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.testutils.assertIsEqualTo
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.LayoutCoordinates
@@ -132,6 +137,31 @@
}
@Test
+ fun bottomNavigation_size_withInsets() {
+ val height = 56.dp
+ val fakeInset = 5.dp
+ rule.setMaterialContentForSizeAssertions {
+ var selectedItem by remember { mutableStateOf(0) }
+ val items = listOf("Songs", "Artists", "Playlists")
+
+ BottomNavigation(
+ windowInsets = WindowInsets(fakeInset, fakeInset, fakeInset, fakeInset),
+ ) {
+ items.forEachIndexed { index, item ->
+ BottomNavigationItem(
+ icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
+ label = { Text(item) },
+ selected = selectedItem == index,
+ onClick = { selectedItem = index }
+ )
+ }
+ }
+ }
+ .assertWidthIsEqualTo(rule.rootWidth())
+ .assertHeightIsEqualTo(height + fakeInset * 2)
+ }
+
+ @Test
fun bottomNavigationItem_sizeAndPositions() {
lateinit var parentCoords: LayoutCoordinates
val itemCoords = mutableMapOf<Int, LayoutCoordinates>()
@@ -175,6 +205,54 @@
}
@Test
+ fun bottomNavigationItem_sizeAndPositions_withInsets() {
+ lateinit var parentCoords: LayoutCoordinates
+ val itemCoords = mutableMapOf<Int, LayoutCoordinates>()
+ val fakeInset = 6.dp
+ rule.setMaterialContent(
+ Modifier.onGloballyPositioned { coords: LayoutCoordinates ->
+ parentCoords = coords
+ }
+ ) {
+ Box {
+ BottomNavigation(
+ windowInsets = WindowInsets(fakeInset, fakeInset, fakeInset, fakeInset),
+ ) {
+ repeat(4) { index ->
+ BottomNavigationItem(
+ icon = { Icon(Icons.Filled.Favorite, null) },
+ label = { Text("Item $index") },
+ selected = index == 0,
+ onClick = {},
+ modifier = Modifier.onGloballyPositioned { coords ->
+ itemCoords[index] = coords
+ }
+ )
+ }
+ }
+ }
+ }
+
+ rule.runOnIdleWithDensity {
+ val totalWidth = parentCoords.size.width
+
+ val expectedItemWidth = (totalWidth - fakeInset.roundToPx() * 2) / 4
+ val expectedItemHeight = 56.dp.roundToPx()
+
+ Truth.assertThat(itemCoords.size).isEqualTo(4)
+
+ itemCoords.forEach { (index, coord) ->
+ Truth.assertThat(coord.size.width).isEqualTo(expectedItemWidth)
+ Truth.assertThat(coord.size.height).isEqualTo(expectedItemHeight)
+ Truth.assertThat(coord.positionInWindow().x)
+ .isEqualTo((expectedItemWidth * index + fakeInset.roundToPx()).toFloat())
+ Truth.assertThat(coord.positionInWindow().y)
+ .isEqualTo(fakeInset.roundToPx().toFloat())
+ }
+ }
+ }
+
+ @Test
fun bottomNavigationItemContent_withLabel_sizeAndPosition() {
rule.setMaterialContent {
Box {
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/NavigationRailTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/NavigationRailTest.kt
index e974548..92b1620 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/NavigationRailTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/NavigationRailTest.kt
@@ -17,6 +17,7 @@
package androidx.compose.material
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
@@ -167,6 +168,34 @@
}
@Test
+ fun navigationRailItem_sizeAndPositions_withInsets() {
+ val itemCoords = mutableMapOf<Int, LayoutCoordinates>()
+ val fakeInset = 6.dp
+ val wi = WindowInsets(fakeInset, fakeInset, fakeInset, fakeInset)
+ rule.setMaterialContent {
+ Box {
+ NavigationRail(
+ windowInsets = wi
+ ) {
+ repeat(4) { index ->
+ NavigationRailItem(
+ icon = { Icon(Icons.Filled.Favorite, null) },
+ label = { Text("Item $index") },
+ selected = index == 0,
+ onClick = {},
+ modifier = Modifier.onGloballyPositioned { coords ->
+ itemCoords[index] = coords
+ }
+ )
+ }
+ }
+ }
+ }
+
+ assertDimension(itemCoords, 72.dp, 72.dp, fakeInset)
+ }
+
+ @Test
fun navigationRailItem_compactSizeAndPositions() {
val itemCoords = mutableMapOf<Int, LayoutCoordinates>()
rule.setMaterialContent {
@@ -202,7 +231,8 @@
label = { Text("Item $index") },
selected = index == 0,
onClick = {},
- modifier = Modifier.width(96.dp)
+ modifier = Modifier
+ .width(96.dp)
.onGloballyPositioned { coords ->
itemCoords[index] = coords
}
@@ -215,10 +245,39 @@
assertDimension(itemCoords, 96.dp, 72.dp)
}
+ @Test
+ fun navigationRailItem_customSizeAndPositions_withInsets() {
+ val itemCoords = mutableMapOf<Int, LayoutCoordinates>()
+ val fakeInset = 14.dp
+ val wi = WindowInsets(fakeInset, fakeInset, fakeInset, fakeInset)
+ rule.setMaterialContent {
+ Box {
+ NavigationRail(windowInsets = wi) {
+ repeat(4) { index ->
+ NavigationRailItem(
+ icon = { Icon(Icons.Filled.Favorite, null) },
+ label = { Text("Item $index") },
+ selected = index == 0,
+ onClick = {},
+ modifier = Modifier
+ .width(96.dp)
+ .onGloballyPositioned { coords ->
+ itemCoords[index] = coords
+ }
+ )
+ }
+ }
+ }
+ }
+
+ assertDimension(itemCoords, 96.dp, 72.dp, fakeInset)
+ }
+
private fun assertDimension(
itemCoords: MutableMap<Int, LayoutCoordinates>,
expectedItemWidth: Dp,
- expectedItemHeight: Dp
+ expectedItemHeight: Dp,
+ inset: Dp = 0.dp
) {
rule.runOnIdleWithDensity {
val expectedItemWidthPx = expectedItemWidth.roundToPx()
@@ -231,7 +290,12 @@
Truth.assertThat(coord.size.width).isEqualTo(expectedItemWidthPx)
Truth.assertThat(coord.size.height).isEqualTo(expectedItemHeightPx)
Truth.assertThat(coord.positionInWindow().y)
- .isEqualTo((expectedItemHeightPx * index + navigationRailPadding).toFloat())
+ .isEqualTo(
+ (expectedItemHeightPx * index +
+ navigationRailPadding + inset.roundToPx()).toFloat()
+ )
+ Truth.assertThat(coord.positionInWindow().x)
+ .isEqualTo(inset.roundToPx().toFloat())
}
}
}
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt
index 4877773..beb3b66 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ScaffoldTest.kt
@@ -21,10 +21,12 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.Composable
@@ -40,6 +42,7 @@
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.layout.positionInRoot
+import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.test.assertHeightIsEqualTo
@@ -51,6 +54,8 @@
import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeLeft
import androidx.compose.ui.test.swipeRight
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize
@@ -59,6 +64,7 @@
import androidx.test.filters.MediumTest
import androidx.test.filters.SdkSuppress
import com.google.common.truth.Truth.assertThat
+import kotlin.math.roundToInt
import kotlinx.coroutines.runBlocking
import org.junit.Ignore
import org.junit.Rule
@@ -562,4 +568,179 @@
}
}
}
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun scaffold_respectsConsumedWindowInsets() {
+ rule.setContent {
+ Box(
+ Modifier
+ .requiredSize(10.dp, 40.dp)
+ .windowInsetsPadding(WindowInsets(top = 10.dp, bottom = 10.dp))
+ ) {
+ Scaffold(
+ contentWindowInsets = WindowInsets(top = 15.dp, bottom = 15.dp)
+ ) { paddingValues ->
+ // Consumed windowInsetsPadding is omitted. This replicates behavior from
+ // Modifier.windowInsetsPadding. (15.dp contentPadding - 10.dp consumedPadding)
+ assertDpIsWithinThreshold(
+ actual = paddingValues.calculateTopPadding(),
+ expected = 5.dp,
+ threshold = roundingError
+ )
+ assertDpIsWithinThreshold(
+ actual = paddingValues.calculateBottomPadding(),
+ expected = 5.dp,
+ threshold = roundingError
+ )
+ Box(
+ Modifier
+ .requiredSize(10.dp)
+ .background(color = Color.White)
+ )
+ }
+ }
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun scaffold_providesInsets_respectsTopAppBar() {
+ rule.setContent {
+ Box(Modifier.requiredSize(10.dp, 40.dp)) {
+ Scaffold(
+ contentWindowInsets = WindowInsets(top = 5.dp, bottom = 3.dp),
+ topBar = {
+ Box(Modifier.requiredSize(0.dp))
+ }
+ ) { paddingValues ->
+ // top is like the collapsed top app bar (i.e. 0dp) + rounding error
+ assertDpIsWithinThreshold(
+ actual = paddingValues.calculateTopPadding(),
+ expected = 0.dp,
+ threshold = roundingError
+ )
+ // bottom is like the insets
+ assertDpIsWithinThreshold(
+ actual = paddingValues.calculateBottomPadding(),
+ expected = 3.dp,
+ threshold = roundingError
+ )
+ Box(
+ Modifier
+ .requiredSize(10.dp)
+ .background(color = Color.White)
+ )
+ }
+ }
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun scaffold_providesInsets_respectsBottomAppBar() {
+ rule.setContent {
+ Box(Modifier.requiredSize(10.dp, 40.dp)) {
+ Scaffold(
+ contentWindowInsets = WindowInsets(top = 5.dp, bottom = 3.dp),
+ bottomBar = {
+ Box(Modifier.requiredSize(10.dp))
+ }
+ ) { paddingValues ->
+ // bottom is like bottom app bar + rounding error
+ assertDpIsWithinThreshold(
+ actual = paddingValues.calculateBottomPadding(),
+ expected = 10.dp,
+ threshold = roundingError
+ )
+ // top is like the insets
+ assertDpIsWithinThreshold(
+ actual = paddingValues.calculateTopPadding(),
+ expected = 5.dp,
+ threshold = roundingError
+ )
+ Box(
+ Modifier
+ .requiredSize(10.dp)
+ .background(color = Color.White)
+ )
+ }
+ }
+ }
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun scaffold_insetsTests_snackbarRespectsInsets() {
+ val hostState = SnackbarHostState()
+ var snackbarSize: IntSize? = null
+ var snackbarPosition: Offset? = null
+ var density: Density? = null
+ rule.setContent {
+ Box(Modifier.requiredSize(10.dp, 40.dp)) {
+ density = LocalDensity.current
+ Scaffold(
+ contentWindowInsets = WindowInsets(top = 5.dp, bottom = 3.dp),
+ snackbarHost = {
+ SnackbarHost(hostState = hostState,
+ modifier = Modifier
+ .onGloballyPositioned {
+ snackbarSize = it.size
+ snackbarPosition = it.positionInRoot()
+ })
+ }
+ ) {
+ Box(
+ Modifier
+ .requiredSize(10.dp)
+ .background(color = Color.White)
+ )
+ }
+ }
+ }
+ val snackbarBottomOffsetDp =
+ with(density!!) { (snackbarPosition!!.y.roundToInt() + snackbarSize!!.height).toDp() }
+ assertThat(rule.rootHeight() - snackbarBottomOffsetDp - 3.dp).isLessThan(1.dp)
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun scaffold_insetsTests_FabRespectsInsets() {
+ var fabSize: IntSize? = null
+ var fabPosition: Offset? = null
+ var density: Density? = null
+ rule.setContent {
+ Box(Modifier.requiredSize(10.dp, 20.dp)) {
+ density = LocalDensity.current
+ Scaffold(
+ contentWindowInsets = WindowInsets(top = 5.dp, bottom = 3.dp),
+ floatingActionButton = {
+ FloatingActionButton(onClick = {},
+ modifier = Modifier
+ .onGloballyPositioned {
+ fabSize = it.size
+ fabPosition = it.positionInRoot()
+ }) {
+ Text("Fab")
+ }
+ },
+ ) {
+ Box(
+ Modifier
+ .requiredSize(10.dp)
+ .background(color = Color.White)
+ )
+ }
+ }
+ }
+ val fabBottomOffsetDp =
+ with(density!!) { (fabPosition!!.y.roundToInt() + fabSize!!.height).toDp() }
+ assertThat(rule.rootHeight() - fabBottomOffsetDp - 3.dp).isLessThan(1.dp)
+ }
+
+ private fun assertDpIsWithinThreshold(actual: Dp, expected: Dp, threshold: Dp) {
+ assertThat(actual.value).isWithin(threshold.value).of(expected.value)
+ }
+
+ private val roundingError = 0.5.dp
}
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/compose/material/material/src/androidMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.android.kt
similarity index 60%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to compose/material/material/src/androidMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.android.kt
index 31d0e6f..fcb25cf 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/compose/material/material/src/androidMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.android.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package androidx.lifecycle.observers;
+package androidx.compose.material
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.systemBars
+import androidx.compose.runtime.Composable
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
- @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
-}
+internal actual val WindowInsets.Companion.systemBarsForVisualComponents: WindowInsets
+ @Composable
+ get() = systemBars
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
index a21b12f..e8bf96b 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
@@ -20,11 +20,15 @@
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@@ -53,6 +57,93 @@
*
* ![App bars: top image](https://developer.android.com/images/reference/androidx/compose/material/app-bars-top.png)
*
+ * This particular overload provides ability to specify [WindowInsets]. Recommended value can be
+ * found in [AppBarDefaults.topAppBarWindowInsets].
+ *
+ * This TopAppBar has slots for a title, navigation icon, and actions. Note that the [title] slot
+ * is inset from the start according to spec - for custom use cases such as horizontally
+ * centering the title, use the other TopAppBar overload for a generic TopAppBar with no
+ * restriction on content.
+ *
+ * @sample androidx.compose.material.samples.SimpleTopAppBar
+ *
+ * @param title The title to be displayed in the center of the TopAppBar
+ * @param windowInsets a window insets that app bar will respect.
+ * @param modifier The [Modifier] to be applied to this TopAppBar
+ * @param navigationIcon The navigation icon displayed at the start of the TopAppBar. This should
+ * typically be an [IconButton] or [IconToggleButton].
+ * @param actions The actions displayed at the end of the TopAppBar. This should typically be
+ * [IconButton]s. The default layout here is a [Row], so icons inside will be placed horizontally.
+ * @param backgroundColor The background color for the TopAppBar. Use [Color.Transparent] to have
+ * no color.
+ * @param contentColor The preferred content color provided by this TopAppBar to its children.
+ * Defaults to either the matching content color for [backgroundColor], or if [backgroundColor]
+ * is not a color from the theme, this will keep the same value set above this TopAppBar.
+ * @param elevation the elevation of this TopAppBar.
+ */
+@Composable
+fun TopAppBar(
+ title: @Composable () -> Unit,
+ windowInsets: WindowInsets,
+ modifier: Modifier = Modifier,
+ navigationIcon: @Composable (() -> Unit)? = null,
+ actions: @Composable RowScope.() -> Unit = {},
+ backgroundColor: Color = MaterialTheme.colors.primarySurface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ elevation: Dp = AppBarDefaults.TopAppBarElevation,
+) {
+ AppBar(
+ backgroundColor,
+ contentColor,
+ elevation,
+ AppBarDefaults.ContentPadding,
+ RectangleShape,
+ windowInsets,
+ modifier
+ ) {
+ if (navigationIcon == null) {
+ Spacer(TitleInsetWithoutIcon)
+ } else {
+ Row(TitleIconModifier, verticalAlignment = Alignment.CenterVertically) {
+ CompositionLocalProvider(
+ LocalContentAlpha provides ContentAlpha.high,
+ content = navigationIcon
+ )
+ }
+ }
+
+ Row(
+ Modifier
+ .fillMaxHeight()
+ .weight(1f),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ ProvideTextStyle(value = MaterialTheme.typography.h6) {
+ CompositionLocalProvider(
+ LocalContentAlpha provides ContentAlpha.high,
+ content = title
+ )
+ }
+ }
+
+ CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
+ Row(
+ Modifier.fillMaxHeight(),
+ horizontalArrangement = Arrangement.End,
+ verticalAlignment = Alignment.CenterVertically,
+ content = actions
+ )
+ }
+ }
+}
+
+/**
+ * <a href="https://material.io/components/app-bars-top" class="external" target="_blank">Material Design top app bar</a>.
+ *
+ * The top app bar displays information and actions relating to the current screen.
+ *
+ * ![App bars: top image](https://developer.android.com/images/reference/androidx/compose/material/app-bars-top.png)
+ *
* This TopAppBar has slots for a title, navigation icon, and actions. Note that the [title] slot
* is inset from the start according to spec - for custom use cases such as horizontally
* centering the title, use the other TopAppBar overload for a generic TopAppBar with no
@@ -83,46 +174,68 @@
contentColor: Color = contentColorFor(backgroundColor),
elevation: Dp = AppBarDefaults.TopAppBarElevation
) {
+ TopAppBar(
+ title,
+ ZeroInsets,
+ modifier,
+ navigationIcon,
+ actions,
+ backgroundColor,
+ contentColor,
+ elevation
+ )
+}
+
+/**
+ * <a href="https://material.io/components/app-bars-top" class="external" target="_blank">Material Design top app bar</a>.
+ *
+ * The top app bar displays information and actions relating to the current screen.
+ *
+ * ![App bars: top image](https://developer.android.com/images/reference/androidx/compose/material/app-bars-top.png)
+ *
+ * This particular overload provides ability to specify [WindowInsets]. Recommended value can be
+ * found in [AppBarDefaults.topAppBarWindowInsets].
+ *
+ * This TopAppBar has no pre-defined slots for content, allowing you to customize the layout of
+ * content inside. See the other TopAppBar overload for a TopAppBar that has opinionated slots
+ * for title, navigation icon, and trailing actions.
+ *
+ * The [LocalContentAlpha] inside this TopAppBar is [ContentAlpha.medium] - this is the default
+ * for trailing and overflow icons. It is recommended that any text, and leading icons at the
+ * start of the TopAppBar use [ContentAlpha.high] instead.
+ *
+ * @param windowInsets a window insets that app bar will respect.
+ * @param modifier The [Modifier] to be applied to this TopAppBar
+ * @param backgroundColor The background color for the TopAppBar. Use [Color.Transparent] to have
+ * no color.
+ * @param contentColor The preferred content color provided by this TopAppBar to its children.
+ * Defaults to either the matching content color for [backgroundColor], or if [backgroundColor] is
+ * not a color from the theme, this will keep the same value set above this TopAppBar.
+ * @param elevation the elevation of this TopAppBar.
+ * @param contentPadding the padding applied to the content of this TopAppBar
+ * @param content the content of this TopAppBar.The default layout here is a [Row],
+ * so content inside will be placed horizontally.
+ */
+@Composable
+fun TopAppBar(
+ windowInsets: WindowInsets,
+ modifier: Modifier = Modifier,
+ backgroundColor: Color = MaterialTheme.colors.primarySurface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ elevation: Dp = AppBarDefaults.TopAppBarElevation,
+ contentPadding: PaddingValues = AppBarDefaults.ContentPadding,
+ content: @Composable RowScope.() -> Unit
+) {
AppBar(
backgroundColor,
contentColor,
elevation,
- AppBarDefaults.ContentPadding,
+ contentPadding,
RectangleShape,
- modifier
- ) {
- if (navigationIcon == null) {
- Spacer(TitleInsetWithoutIcon)
- } else {
- Row(TitleIconModifier, verticalAlignment = Alignment.CenterVertically) {
- CompositionLocalProvider(
- LocalContentAlpha provides ContentAlpha.high,
- content = navigationIcon
- )
- }
- }
-
- Row(
- Modifier.fillMaxHeight().weight(1f),
- verticalAlignment = Alignment.CenterVertically
- ) {
- ProvideTextStyle(value = MaterialTheme.typography.h6) {
- CompositionLocalProvider(
- LocalContentAlpha provides ContentAlpha.high,
- content = title
- )
- }
- }
-
- CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
- Row(
- Modifier.fillMaxHeight(),
- horizontalArrangement = Arrangement.End,
- verticalAlignment = Alignment.CenterVertically,
- content = actions
- )
- }
- }
+ windowInsets,
+ modifier = modifier,
+ content = content
+ )
}
/**
@@ -166,6 +279,7 @@
elevation,
contentPadding,
RectangleShape,
+ ZeroInsets,
modifier = modifier,
content = content
)
@@ -178,6 +292,79 @@
*
* ![App bars: bottom image](https://developer.android.com/images/reference/androidx/compose/material/app-bars-bottom.png)
*
+ * This particular overload provides ability to specify [WindowInsets]. Recommended value can be
+ * found in [AppBarDefaults.bottomAppBarWindowInsets].
+ *
+ * It can also optionally display a [FloatingActionButton], which is either overlaid
+ * on top of the BottomAppBar, or inset, carving a cutout in the BottomAppBar.
+ *
+ * See [BottomAppBar anatomy](https://material.io/components/app-bars-bottom/#anatomy) for the
+ * recommended content depending on the [FloatingActionButton] position.
+ *
+ * Note that when you pass a non-null [cutoutShape] this makes the AppBar shape concave. The shadows
+ * for such shapes will not be drawn on Android versions less than 10.
+ *
+ * The [LocalContentAlpha] inside a BottomAppBar is [ContentAlpha.medium] - this is the default
+ * for trailing and overflow icons. It is recommended that any leading icons at the start of the
+ * BottomAppBar, such as a menu icon, use [ContentAlpha.high] instead. This is demonstrated in the
+ * sample below.
+ *
+ * Also see [BottomNavigation].
+ *
+ * @sample androidx.compose.material.samples.SimpleBottomAppBar
+ *
+ * @param windowInsets a window insets that app bar will respect.
+ * @param modifier The [Modifier] to be applied to this BottomAppBar
+ * @param backgroundColor The background color for the BottomAppBar. Use [Color.Transparent] to
+ * have no color.
+ * @param contentColor The preferred content color provided by this BottomAppBar to its children.
+ * Defaults to either the matching content color for [backgroundColor], or if [backgroundColor] is
+ * not a color from the theme, this will keep the same value set above this BottomAppBar.
+ * @param cutoutShape the shape of the cutout that will be added to the BottomAppBar - this
+ * should typically be the same shape used inside the [FloatingActionButton], when [BottomAppBar]
+ * and [FloatingActionButton] are being used together in [Scaffold]. This shape will be drawn with
+ * an offset around all sides. If null, where will be no cutout.
+ * @param elevation the elevation of this BottomAppBar.
+ * @param contentPadding the padding applied to the content of this BottomAppBar
+ * @param content the content of this BottomAppBar. The default layout here is a [Row],
+ * so content inside will be placed horizontally.
+ */
+@Composable
+fun BottomAppBar(
+ windowInsets: WindowInsets,
+ modifier: Modifier = Modifier,
+ backgroundColor: Color = MaterialTheme.colors.primarySurface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ cutoutShape: Shape? = null,
+ elevation: Dp = AppBarDefaults.BottomAppBarElevation,
+ contentPadding: PaddingValues = AppBarDefaults.ContentPadding,
+ content: @Composable RowScope.() -> Unit
+) {
+ val fabPlacement = LocalFabPlacement.current
+ val shape = if (cutoutShape != null && fabPlacement?.isDocked == true) {
+ BottomAppBarCutoutShape(cutoutShape, fabPlacement)
+ } else {
+ RectangleShape
+ }
+ AppBar(
+ backgroundColor,
+ contentColor,
+ elevation,
+ contentPadding,
+ shape,
+ windowInsets,
+ modifier,
+ content
+ )
+}
+
+/**
+ * <a href="https://material.io/components/app-bars-bottom" class="external" target="_blank">Material Design bottom app bar</a>.
+ *
+ * A bottom app bar displays navigation and key actions at the bottom of screens.
+ *
+ * ![App bars: bottom image](https://developer.android.com/images/reference/androidx/compose/material/app-bars-bottom.png)
+ *
* It can also optionally display a [FloatingActionButton], which is either overlaid
* on top of the BottomAppBar, or inset, carving a cutout in the BottomAppBar.
*
@@ -233,6 +420,7 @@
elevation,
contentPadding,
shape,
+ ZeroInsets,
modifier,
content
)
@@ -261,6 +449,24 @@
start = AppBarHorizontalPadding,
end = AppBarHorizontalPadding
)
+
+ /**
+ * Recommended insets to be used and consumed by the top app bars
+ */
+ val topAppBarWindowInsets: WindowInsets
+ @Composable
+ get() = WindowInsets.systemBarsForVisualComponents
+ .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top)
+
+ /**
+ * Recommended insets to be used and consumed by the bottom app bars
+ */
+ val bottomAppBarWindowInsets: WindowInsets
+ @Composable
+ get() {
+ return WindowInsets.systemBarsForVisualComponents
+ .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
+ }
}
// TODO: consider exposing this in the shape package, for a generic cutout shape - might be useful
@@ -508,6 +714,7 @@
elevation: Dp,
contentPadding: PaddingValues,
shape: Shape,
+ windowInsets: WindowInsets,
modifier: Modifier = Modifier,
content: @Composable RowScope.() -> Unit
) {
@@ -520,7 +727,9 @@
) {
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Row(
- Modifier.fillMaxWidth()
+ Modifier
+ .fillMaxWidth()
+ .windowInsetsPadding(windowInsets)
.padding(contentPadding)
.height(AppBarHeight),
horizontalArrangement = Arrangement.Start,
@@ -544,3 +753,5 @@
private val BottomAppBarCutoutOffset = 8.dp
// How far from the notch the rounded edges start
private val BottomAppBarRoundedEdgeRadius = 4.dp
+
+private val ZeroInsets = WindowInsets(0.dp)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
index ee0e23d..fb53a4d 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/BottomNavigation.kt
@@ -27,9 +27,13 @@
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.ripple.rememberRipple
@@ -65,6 +69,66 @@
*
* ![Bottom navigation image](https://developer.android.com/images/reference/androidx/compose/material/bottom-navigation.png)
*
+ * This particular overload provides ability to specify [WindowInsets]. Recommended value can be
+ * found in [BottomNavigationDefaults.windowInsets].
+ *
+ * BottomNavigation should contain multiple [BottomNavigationItem]s, each representing a singular
+ * destination.
+ *
+ * A simple example looks like:
+ *
+ * @sample androidx.compose.material.samples.BottomNavigationSample
+ *
+ * See [BottomNavigationItem] for configuration specific to each item, and not the overall
+ * BottomNavigation component.
+ *
+ * For more information, see [Bottom Navigation](https://material.io/components/bottom-navigation/)
+ *
+ * @param windowInsets a window insets that bottom navigation will respect.
+ * @param modifier optional [Modifier] for this BottomNavigation
+ * @param backgroundColor The background color for this BottomNavigation
+ * @param contentColor The preferred content color provided by this BottomNavigation to its
+ * children. Defaults to either the matching content color for [backgroundColor], or if
+ * [backgroundColor] is not a color from the theme, this will keep the same value set above this
+ * BottomNavigation.
+ * @param elevation elevation for this BottomNavigation
+ * @param content destinations inside this BottomNavigation, this should contain multiple
+ * [BottomNavigationItem]s
+ */
+@Composable
+fun BottomNavigation(
+ windowInsets: WindowInsets,
+ modifier: Modifier = Modifier,
+ backgroundColor: Color = MaterialTheme.colors.primarySurface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ elevation: Dp = BottomNavigationDefaults.Elevation,
+ content: @Composable RowScope.() -> Unit
+) {
+ Surface(
+ color = backgroundColor,
+ contentColor = contentColor,
+ elevation = elevation,
+ modifier = modifier
+ ) {
+ Row(
+ Modifier
+ .fillMaxWidth()
+ .windowInsetsPadding(windowInsets)
+ .height(BottomNavigationHeight)
+ .selectableGroup(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ content = content
+ )
+ }
+}
+
+/**
+ * <a href="https://material.io/components/bottom-navigation" class="external" target="_blank">Material Design bottom navigation</a>.
+ *
+ * Bottom navigation bars allow movement between primary destinations in an app.
+ *
+ * ![Bottom navigation image](https://developer.android.com/images/reference/androidx/compose/material/bottom-navigation.png)
+ *
* BottomNavigation should contain multiple [BottomNavigationItem]s, each representing a singular
* destination.
*
@@ -95,21 +159,7 @@
elevation: Dp = BottomNavigationDefaults.Elevation,
content: @Composable RowScope.() -> Unit
) {
- Surface(
- color = backgroundColor,
- contentColor = contentColor,
- elevation = elevation,
- modifier = modifier
- ) {
- Row(
- Modifier
- .fillMaxWidth()
- .height(BottomNavigationHeight)
- .selectableGroup(),
- horizontalArrangement = Arrangement.SpaceBetween,
- content = content
- )
- }
+ BottomNavigation(ZeroInsets, modifier, backgroundColor, contentColor, elevation, content)
}
/**
@@ -205,6 +255,14 @@
* Default elevation used for [BottomNavigation].
*/
val Elevation = 8.dp
+
+ /**
+ * Recommended window insets to be used and consumed by bottom navigation
+ */
+ val windowInsets: WindowInsets
+ @Composable
+ get() = WindowInsets.systemBarsForVisualComponents
+ .only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
}
/**
@@ -397,3 +455,5 @@
* the text baseline and the bottom of the icon placed above it.
*/
private val CombinedItemTextBaseline = 12.dp
+
+private val ZeroInsets = WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/MutableWindowInsets.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/MutableWindowInsets.kt
new file mode 100644
index 0000000..99be9b7
--- /dev/null
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/MutableWindowInsets.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.material
+
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+
+/**
+ * A [WindowInsets] whose values can change without changing the instance. This is useful
+ * to avoid recomposition when [WindowInsets] can change.
+ *
+ * Copied from [androidx.compose.foundation.layout.MutableWindowInsets], which is marked as
+ * experimental and thus cannot be used cross-module.
+ */
+internal class MutableWindowInsets(
+ initialInsets: WindowInsets = WindowInsets(0, 0, 0, 0)
+) : WindowInsets {
+ /**
+ * The [WindowInsets] that are used for [left][getLeft], [top][getTop], [right][getRight],
+ * and [bottom][getBottom] values.
+ */
+ var insets by mutableStateOf(initialInsets)
+
+ override fun getLeft(density: Density, layoutDirection: LayoutDirection): Int =
+ insets.getLeft(density, layoutDirection)
+ override fun getTop(density: Density): Int = insets.getTop(density)
+ override fun getRight(density: Density, layoutDirection: LayoutDirection): Int =
+ insets.getRight(density, layoutDirection)
+ override fun getBottom(density: Density): Int = insets.getBottom(density)
+}
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/NavigationRail.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/NavigationRail.kt
index e2b37e2..49943de 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/NavigationRail.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/NavigationRail.kt
@@ -27,10 +27,14 @@
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.ripple.rememberRipple
@@ -67,6 +71,76 @@
*
* ![Navigation rail image](https://developer.android.com/images/reference/androidx/compose/material/navigation-rail.png)
*
+ * This particular overload provides ability to specify [WindowInsets]. Recommended value can be
+ * found in [NavigationRailDefaults.windowInsets].
+ *
+ * NavigationRail should contain multiple [NavigationRailItem]s, each representing a singular
+ * destination.
+ *
+ * A simple example looks like:
+ *
+ * @sample androidx.compose.material.samples.NavigationRailSample
+ *
+ * See [NavigationRailItem] for configuration specific to each item, and not the overall
+ * NavigationRail component.
+ *
+ * For more information, see [Navigation Rail](https://material.io/components/navigation-rail/)
+ *
+ * @param windowInsets a window insets that navigation rail will respect
+ * @param modifier optional [Modifier] for this NavigationRail
+ * @param backgroundColor The background color for this NavigationRail
+ * @param contentColor The preferred content color provided by this NavigationRail to its
+ * children. Defaults to either the matching content color for [backgroundColor], or if
+ * [backgroundColor] is not a color from the theme, this will keep the same value set above this
+ * NavigationRail.
+ * @param elevation elevation for this NavigationRail
+ * @param header an optional header that may hold a [FloatingActionButton] or a logo
+ * @param content destinations inside this NavigationRail, this should contain multiple
+ * [NavigationRailItem]s
+ */
+@Composable
+fun NavigationRail(
+ windowInsets: WindowInsets,
+ modifier: Modifier = Modifier,
+ backgroundColor: Color = MaterialTheme.colors.surface,
+ contentColor: Color = contentColorFor(backgroundColor),
+ elevation: Dp = NavigationRailDefaults.Elevation,
+ header: @Composable (ColumnScope.() -> Unit)? = null,
+ content: @Composable ColumnScope.() -> Unit
+) {
+ Surface(
+ modifier = modifier,
+ color = backgroundColor,
+ contentColor = contentColor,
+ elevation = elevation
+ ) {
+ Column(
+ Modifier
+ .fillMaxHeight()
+ .windowInsetsPadding(windowInsets)
+ .padding(vertical = NavigationRailPadding)
+ .selectableGroup(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ if (header != null) {
+ header()
+ Spacer(Modifier.height(HeaderPadding))
+ }
+ content()
+ }
+ }
+}
+
+/**
+ * <a href="https://material.io/components/navigation-rail" class="external" target="_blank">Material Design navigation rail</a>.
+ *
+ * A Navigation Rail is a side navigation component that allows movement between primary
+ * destinations in an app. A navigation rail should be used to display three to seven app
+ * destinations and, optionally, a [FloatingActionButton] or a logo inside [header]. Each
+ * destination is typically represented by an icon and an optional text label.
+ *
+ * ![Navigation rail image](https://developer.android.com/images/reference/androidx/compose/material/navigation-rail.png)
+ *
* NavigationRail should contain multiple [NavigationRailItem]s, each representing a singular
* destination.
*
@@ -99,26 +173,7 @@
header: @Composable (ColumnScope.() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit
) {
- Surface(
- modifier = modifier,
- color = backgroundColor,
- contentColor = contentColor,
- elevation = elevation
- ) {
- Column(
- Modifier
- .fillMaxHeight()
- .padding(vertical = NavigationRailPadding)
- .selectableGroup(),
- horizontalAlignment = Alignment.CenterHorizontally,
- ) {
- if (header != null) {
- header()
- Spacer(Modifier.height(HeaderPadding))
- }
- content()
- }
- }
+ NavigationRail(ZeroInsets, modifier, backgroundColor, contentColor, elevation, header, content)
}
/**
@@ -183,7 +238,8 @@
role = Role.Tab,
interactionSource = interactionSource,
indication = ripple
- ).size(itemSize),
+ )
+ .size(itemSize),
contentAlignment = Alignment.Center
) {
NavigationRailTransition(
@@ -210,6 +266,14 @@
* Default elevation used for [NavigationRail].
*/
val Elevation = 8.dp
+
+ /**
+ * Recommended window insets for navigation rail.
+ */
+ val windowInsets: WindowInsets
+ @Composable
+ get() = WindowInsets.systemBarsForVisualComponents
+ .only(WindowInsetsSides.Vertical + WindowInsetsSides.Start)
}
/**
@@ -404,3 +468,5 @@
* The space between the icon and the top of the container when an item contains a label and icon.
*/
private val ItemIconTopOffset = 14.dp
+
+private val ZeroInsets = WindowInsets(0.dp)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
index 502606b..5da9479 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Scaffold.kt
@@ -18,6 +18,13 @@
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.calculateEndPadding
+import androidx.compose.foundation.layout.calculateStartPadding
+import androidx.compose.foundation.layout.consumeWindowInsets
+import androidx.compose.foundation.layout.exclude
+import androidx.compose.foundation.layout.onConsumedWindowInsetsChanged
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
@@ -32,6 +39,7 @@
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.offset
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMap
import androidx.compose.ui.util.fastMaxBy
@@ -114,6 +122,143 @@
* which uses a backdrop as the centerpiece of the screen, and [BottomSheetScaffold], which uses
* a persistent bottom sheet as the centerpiece of the screen.
*
+ * This particular overload provides ability to specify [WindowInsets]. Recommended value can be
+ * found in [ScaffoldDefaults.contentWindowInsets].
+ *
+ * Simple example of a Scaffold with [TopAppBar], [FloatingActionButton] and drawer:
+ *
+ * @sample androidx.compose.material.samples.SimpleScaffoldWithTopBar
+ *
+ * More fancy usage with [BottomAppBar] with cutout and docked [FloatingActionButton], which
+ * animates it's shape when clicked:
+ *
+ * @sample androidx.compose.material.samples.ScaffoldWithBottomBarAndCutout
+ *
+ * To show a [Snackbar], use [SnackbarHostState.showSnackbar]. Scaffold state already
+ * have [ScaffoldState.snackbarHostState] when created
+ *
+ * @sample androidx.compose.material.samples.ScaffoldWithSimpleSnackbar
+ *
+ * @param contentWindowInsets window insets to be passed to [content] slot via [PaddingValues]
+ * params. Scaffold will take the insets into account from the top/bottom only if the [topBar]/
+ * [bottomBar] are not present, as the scaffold expect [topBar]/[bottomBar] to handle insets
+ * instead. Any insets consumed by other insets padding modifiers or [consumeWindowInsets] on a
+ * parent layout will be excluded from [contentWindowInsets].
+ * @param modifier optional Modifier for the root of the [Scaffold]
+ * @param scaffoldState state of this scaffold widget. It contains the state of the screen, e.g.
+ * variables to provide manual control over the drawer behavior, sizes of components, etc
+ * @param topBar top app bar of the screen. Consider using [TopAppBar].
+ * @param bottomBar bottom bar of the screen. Consider using [BottomAppBar].
+ * @param snackbarHost component to host [Snackbar]s that are pushed to be shown via
+ * [SnackbarHostState.showSnackbar]. Usually it's a [SnackbarHost]
+ * @param floatingActionButton Main action button of your screen. Consider using
+ * [FloatingActionButton] for this slot.
+ * @param floatingActionButtonPosition position of the FAB on the screen. See [FabPosition] for
+ * possible options available.
+ * @param isFloatingActionButtonDocked whether [floatingActionButton] should overlap with
+ * [bottomBar] for half a height, if [bottomBar] exists. Ignored if there's no [bottomBar] or no
+ * [floatingActionButton].
+ * @param drawerContent content of the Drawer sheet that can be pulled from the left side (right
+ * for RTL).
+ * @param drawerGesturesEnabled whether or not drawer (if set) can be interacted with via gestures
+ * @param drawerShape shape of the drawer sheet (if set)
+ * @param drawerElevation drawer sheet elevation. This controls the size of the shadow
+ * below the drawer sheet (if set)
+ * @param drawerBackgroundColor background color to be used for the drawer sheet
+ * @param drawerContentColor color of the content to use inside the drawer sheet. Defaults to
+ * either the matching content color for [drawerBackgroundColor], or, if it is not a color from
+ * the theme, this will keep the same value set above this Surface.
+ * @param drawerScrimColor color of the scrim that obscures content when the drawer is open
+ * @param backgroundColor background of the scaffold body
+ * @param contentColor color of the content in scaffold body. Defaults to either the matching
+ * content color for [backgroundColor], or, if it is not a color from the theme, this will keep
+ * the same value set above this Surface.
+ * @param content content of your screen. The lambda receives an [PaddingValues] that should be
+ * applied to the content root via Modifier.padding to properly offset top and bottom bars. If
+ * you're using VerticalScroller, apply this modifier to the child of the scroller, and not on
+ * the scroller itself.
+ */
+@Composable
+fun Scaffold(
+ contentWindowInsets: WindowInsets,
+ modifier: Modifier = Modifier,
+ scaffoldState: ScaffoldState = rememberScaffoldState(),
+ topBar: @Composable () -> Unit = {},
+ bottomBar: @Composable () -> Unit = {},
+ snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
+ floatingActionButton: @Composable () -> Unit = {},
+ floatingActionButtonPosition: FabPosition = FabPosition.End,
+ isFloatingActionButtonDocked: Boolean = false,
+ drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
+ drawerGesturesEnabled: Boolean = true,
+ drawerShape: Shape = MaterialTheme.shapes.large,
+ drawerElevation: Dp = DrawerDefaults.Elevation,
+ drawerBackgroundColor: Color = MaterialTheme.colors.surface,
+ drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
+ drawerScrimColor: Color = DrawerDefaults.scrimColor,
+ backgroundColor: Color = MaterialTheme.colors.background,
+ contentColor: Color = contentColorFor(backgroundColor),
+ content: @Composable (PaddingValues) -> Unit
+) {
+ val safeInsets = remember(contentWindowInsets) {
+ MutableWindowInsets(contentWindowInsets)
+ }
+ val child = @Composable { childModifier: Modifier ->
+ Surface(
+ modifier = childModifier
+ .onConsumedWindowInsetsChanged { consumedWindowInsets ->
+ // Exclude currently consumed window insets from user provided contentWindowInsets
+ safeInsets.insets = contentWindowInsets.exclude(consumedWindowInsets)
+ },
+ color = backgroundColor,
+ contentColor = contentColor
+ ) {
+ ScaffoldLayout(
+ isFabDocked = isFloatingActionButtonDocked,
+ fabPosition = floatingActionButtonPosition,
+ topBar = topBar,
+ content = content,
+ contentWindowInsets = safeInsets,
+ snackbar = {
+ snackbarHost(scaffoldState.snackbarHostState)
+ },
+ fab = floatingActionButton,
+ bottomBar = bottomBar
+ )
+ }
+ }
+
+ if (drawerContent != null) {
+ ModalDrawer(
+ modifier = modifier,
+ drawerState = scaffoldState.drawerState,
+ gesturesEnabled = drawerGesturesEnabled,
+ drawerContent = drawerContent,
+ drawerShape = drawerShape,
+ drawerElevation = drawerElevation,
+ drawerBackgroundColor = drawerBackgroundColor,
+ drawerContentColor = drawerContentColor,
+ scrimColor = drawerScrimColor,
+ content = { child(Modifier) }
+ )
+ } else {
+ child(modifier)
+ }
+}
+
+/**
+ * <a href="https://material.io/design/layout/understanding-layout.html" class="external" target="_blank">Material Design layout</a>.
+ *
+ * Scaffold implements the basic material design visual layout structure.
+ *
+ * This component provides API to put together several material components to construct your
+ * screen, by ensuring proper layout strategy for them and collecting necessary data so these
+ * components will work together correctly.
+ *
+ * For similar components that implement different layout structures, see [BackdropScaffold],
+ * which uses a backdrop as the centerpiece of the screen, and [BottomSheetScaffold], which uses
+ * a persistent bottom sheet as the centerpiece of the screen.
+ *
* Simple example of a Scaffold with [TopAppBar], [FloatingActionButton] and drawer:
*
* @sample androidx.compose.material.samples.SimpleScaffoldWithTopBar
@@ -183,38 +328,39 @@
contentColor: Color = contentColorFor(backgroundColor),
content: @Composable (PaddingValues) -> Unit
) {
- val child = @Composable { childModifier: Modifier ->
- Surface(modifier = childModifier, color = backgroundColor, contentColor = contentColor) {
- ScaffoldLayout(
- isFabDocked = isFloatingActionButtonDocked,
- fabPosition = floatingActionButtonPosition,
- topBar = topBar,
- content = content,
- snackbar = {
- snackbarHost(scaffoldState.snackbarHostState)
- },
- fab = floatingActionButton,
- bottomBar = bottomBar
- )
- }
- }
+ Scaffold(
+ WindowInsets(0.dp),
+ modifier,
+ scaffoldState,
+ topBar,
+ bottomBar,
+ snackbarHost,
+ floatingActionButton,
+ floatingActionButtonPosition,
+ isFloatingActionButtonDocked,
+ drawerContent,
+ drawerGesturesEnabled,
+ drawerShape,
+ drawerElevation,
+ drawerBackgroundColor,
+ drawerContentColor,
+ drawerScrimColor,
+ backgroundColor,
+ contentColor,
+ content
+ )
+}
- if (drawerContent != null) {
- ModalDrawer(
- modifier = modifier,
- drawerState = scaffoldState.drawerState,
- gesturesEnabled = drawerGesturesEnabled,
- drawerContent = drawerContent,
- drawerShape = drawerShape,
- drawerElevation = drawerElevation,
- drawerBackgroundColor = drawerBackgroundColor,
- drawerContentColor = drawerContentColor,
- scrimColor = drawerScrimColor,
- content = { child(Modifier) }
- )
- } else {
- child(modifier)
- }
+/**
+ * Object containing various default values for [Scaffold] component.
+ */
+object ScaffoldDefaults {
+ /**
+ * Recommended insets to be used and consumed by the scaffold content slot
+ */
+ val contentWindowInsets: WindowInsets
+ @Composable
+ get() = WindowInsets.systemBarsForVisualComponents
}
/**
@@ -239,6 +385,7 @@
content: @Composable @UiComposable (PaddingValues) -> Unit,
snackbar: @Composable @UiComposable () -> Unit,
fab: @Composable @UiComposable () -> Unit,
+ contentWindowInsets: WindowInsets,
bottomBar: @Composable @UiComposable () -> Unit
) {
SubcomposeLayout { constraints ->
@@ -254,15 +401,38 @@
val topBarHeight = topBarPlaceables.fastMaxBy { it.height }?.height ?: 0
- val snackbarPlaceables = subcompose(ScaffoldLayoutContent.Snackbar, snackbar).fastMap {
- it.measure(looseConstraints)
+ val snackbarPlaceables = subcompose(ScaffoldLayoutContent.Snackbar, snackbar).map {
+ // respect only bottom and horizontal for snackbar and fab
+ val leftInset = contentWindowInsets
+ .getLeft(this@SubcomposeLayout, layoutDirection)
+ val rightInset = contentWindowInsets
+ .getRight(this@SubcomposeLayout, layoutDirection)
+ val bottomInset = contentWindowInsets.getBottom(this@SubcomposeLayout)
+ // offset the snackbar constraints by the insets values
+ it.measure(
+ looseConstraints.offset(
+ -leftInset - rightInset,
+ -bottomInset
+ )
+ )
}
val snackbarHeight = snackbarPlaceables.fastMaxBy { it.height }?.height ?: 0
val fabPlaceables =
subcompose(ScaffoldLayoutContent.Fab, fab).fastMap { measurable ->
- measurable.measure(looseConstraints)
+ // respect only bottom and horizontal for snackbar and fab
+ val leftInset =
+ contentWindowInsets.getLeft(this@SubcomposeLayout, layoutDirection)
+ val rightInset =
+ contentWindowInsets.getRight(this@SubcomposeLayout, layoutDirection)
+ val bottomInset = contentWindowInsets.getBottom(this@SubcomposeLayout)
+ measurable.measure(
+ looseConstraints.offset(
+ -leftInset - rightInset,
+ -bottomInset
+ )
+ )
}
val fabPlacement = if (fabPlaceables.isNotEmpty()) {
@@ -308,10 +478,11 @@
)
}.fastMap { it.measure(looseConstraints) }
- val bottomBarHeight = bottomBarPlaceables.fastMaxBy { it.height }?.height ?: 0
+ val bottomBarHeight = bottomBarPlaceables.fastMaxBy { it.height }?.height
val fabOffsetFromBottom = fabPlacement?.let {
- if (bottomBarHeight == 0) {
- it.height + FabSpacing.roundToPx()
+ if (bottomBarHeight == null) {
+ it.height + FabSpacing.roundToPx() +
+ contentWindowInsets.getBottom(this@SubcomposeLayout)
} else {
if (isFabDocked) {
// Total height is the bottom bar height + half the FAB height
@@ -325,7 +496,9 @@
}
val snackbarOffsetFromBottom = if (snackbarHeight != 0) {
- snackbarHeight + (fabOffsetFromBottom ?: bottomBarHeight)
+ snackbarHeight +
+ (fabOffsetFromBottom ?: bottomBarHeight
+ ?: contentWindowInsets.getBottom(this@SubcomposeLayout))
} else {
0
}
@@ -333,7 +506,23 @@
val bodyContentHeight = layoutHeight - topBarHeight
val bodyContentPlaceables = subcompose(ScaffoldLayoutContent.MainContent) {
- val innerPadding = PaddingValues(bottom = bottomBarHeight.toDp())
+ val insets = contentWindowInsets.asPaddingValues(this@SubcomposeLayout)
+ val innerPadding = PaddingValues(
+ top =
+ if (topBarPlaceables.isEmpty()) {
+ insets.calculateTopPadding()
+ } else {
+ 0.dp
+ },
+ bottom =
+ if (bottomBarPlaceables.isEmpty() || bottomBarHeight == null) {
+ insets.calculateBottomPadding()
+ } else {
+ bottomBarHeight.toDp()
+ },
+ start = insets.calculateStartPadding((this@SubcomposeLayout).layoutDirection),
+ end = insets.calculateEndPadding((this@SubcomposeLayout).layoutDirection)
+ )
content(innerPadding)
}.fastMap { it.measure(looseConstraints.copy(maxHeight = bodyContentHeight)) }
@@ -350,7 +539,7 @@
}
// The bottom bar is always at the bottom of the layout
bottomBarPlaceables.fastForEach {
- it.place(0, layoutHeight - bottomBarHeight)
+ it.place(0, layoutHeight - (bottomBarHeight ?: 0))
}
// Explicitly not using placeRelative here as `leftOffset` already accounts for RTL
fabPlaceables.fastForEach {
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.kt
similarity index 60%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to compose/material/material/src/commonMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.kt
index 31d0e6f..dee6110 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,10 @@
* limitations under the License.
*/
-package androidx.lifecycle.observers;
+package androidx.compose.material
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.runtime.Composable
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
- @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
-}
+internal expect val WindowInsets.Companion.systemBarsForVisualComponents: WindowInsets
+ @Composable get
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.desktop.kt
similarity index 60%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to compose/material/material/src/desktopMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.desktop.kt
index 31d0e6f..0d5c025 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/compose/material/material/src/desktopMain/kotlin/androidx/compose/material/SystemBarsDefaultInsets.desktop.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package androidx.lifecycle.observers;
+package androidx.compose.material
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.unit.dp
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
- @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
-}
+internal actual val WindowInsets.Companion.systemBarsForVisualComponents: WindowInsets
+ @Composable
+ get() = WindowInsets(0.dp, 0.dp, 0.dp, 0.dp)
diff --git a/compose/material3/material3-adaptive/api/current.txt b/compose/material3/material3-adaptive/api/current.txt
index bf5b32a..af140b8 100644
--- a/compose/material3/material3-adaptive/api/current.txt
+++ b/compose/material3/material3-adaptive/api/current.txt
@@ -96,6 +96,77 @@
property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
}
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum NavigationSuiteAlignment {
+ method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment[] values();
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment BottomHorizontal;
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment EndVertical;
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment StartVertical;
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment TopHorizontal;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteColors {
+ method public long getNavigationBarContainerColor();
+ method public long getNavigationBarContentColor();
+ method public long getNavigationDrawerContainerColor();
+ method public long getNavigationDrawerContentColor();
+ method public long getNavigationRailContainerColor();
+ method public long getNavigationRailContentColor();
+ property public final long navigationBarContainerColor;
+ property public final long navigationBarContentColor;
+ property public final long navigationDrawerContainerColor;
+ property public final long navigationDrawerContentColor;
+ property public final long navigationRailContainerColor;
+ property public final long navigationRailContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteDefaults {
+ method public String calculateFromAdaptiveInfo(androidx.compose.material3.adaptive.WindowAdaptiveInfo adaptiveInfo);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.adaptive.NavigationSuiteColors colors(optional long navigationBarContainerColor, optional long navigationBarContentColor, optional long navigationRailContainerColor, optional long navigationRailContentColor, optional long navigationDrawerContainerColor, optional long navigationDrawerContentColor);
+ method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationBarAlignment();
+ method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationDrawerAlignment();
+ method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationRailAlignment();
+ property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationBarAlignment;
+ property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationDrawerAlignment;
+ property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationRailAlignment;
+ field public static final androidx.compose.material3.adaptive.NavigationSuiteDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteItemColors {
+ method public androidx.compose.material3.NavigationBarItemColors getNavigationBarItemColors();
+ method public androidx.compose.material3.NavigationDrawerItemColors getNavigationDrawerItemColors();
+ method public androidx.compose.material3.NavigationRailItemColors getNavigationRailItemColors();
+ property public final androidx.compose.material3.NavigationBarItemColors navigationBarItemColors;
+ property public final androidx.compose.material3.NavigationDrawerItemColors navigationDrawerItemColors;
+ property public final androidx.compose.material3.NavigationRailItemColors navigationRailItemColors;
+ }
+
+ public final class NavigationSuiteScaffoldKt {
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuite(androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope, optional androidx.compose.ui.Modifier modifier, optional String layoutType, optional androidx.compose.material3.adaptive.NavigationSuiteColors colors, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuiteScaffold(kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope,kotlin.Unit> navigationSuite, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScaffoldScope {
+ method public androidx.compose.ui.Modifier alignment(androidx.compose.ui.Modifier, androidx.compose.material3.adaptive.NavigationSuiteAlignment alignment);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScope {
+ method public void item(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.material3.adaptive.NavigationSuiteItemColors? colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class NavigationSuiteType {
+ field public static final androidx.compose.material3.adaptive.NavigationSuiteType.Companion Companion;
+ }
+
+ public static final class NavigationSuiteType.Companion {
+ method public String getNavigationBar();
+ method public String getNavigationDrawer();
+ method public String getNavigationRail();
+ property public final String NavigationBar;
+ property public final String NavigationDrawer;
+ property public final String NavigationRail;
+ }
+
@SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class PaneAdaptedValue {
field public static final androidx.compose.material3.adaptive.PaneAdaptedValue.Companion Companion;
}
diff --git a/compose/material3/material3-adaptive/api/restricted_current.txt b/compose/material3/material3-adaptive/api/restricted_current.txt
index bf5b32a..af140b8 100644
--- a/compose/material3/material3-adaptive/api/restricted_current.txt
+++ b/compose/material3/material3-adaptive/api/restricted_current.txt
@@ -96,6 +96,77 @@
property public abstract androidx.compose.material3.adaptive.ThreePaneScaffoldValue layoutValue;
}
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public enum NavigationSuiteAlignment {
+ method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.compose.material3.adaptive.NavigationSuiteAlignment[] values();
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment BottomHorizontal;
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment EndVertical;
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment StartVertical;
+ enum_constant public static final androidx.compose.material3.adaptive.NavigationSuiteAlignment TopHorizontal;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteColors {
+ method public long getNavigationBarContainerColor();
+ method public long getNavigationBarContentColor();
+ method public long getNavigationDrawerContainerColor();
+ method public long getNavigationDrawerContentColor();
+ method public long getNavigationRailContainerColor();
+ method public long getNavigationRailContentColor();
+ property public final long navigationBarContainerColor;
+ property public final long navigationBarContentColor;
+ property public final long navigationDrawerContainerColor;
+ property public final long navigationDrawerContentColor;
+ property public final long navigationRailContainerColor;
+ property public final long navigationRailContentColor;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteDefaults {
+ method public String calculateFromAdaptiveInfo(androidx.compose.material3.adaptive.WindowAdaptiveInfo adaptiveInfo);
+ method @androidx.compose.runtime.Composable public androidx.compose.material3.adaptive.NavigationSuiteColors colors(optional long navigationBarContainerColor, optional long navigationBarContentColor, optional long navigationRailContainerColor, optional long navigationRailContentColor, optional long navigationDrawerContainerColor, optional long navigationDrawerContentColor);
+ method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationBarAlignment();
+ method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationDrawerAlignment();
+ method public androidx.compose.material3.adaptive.NavigationSuiteAlignment getNavigationRailAlignment();
+ property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationBarAlignment;
+ property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationDrawerAlignment;
+ property public final androidx.compose.material3.adaptive.NavigationSuiteAlignment NavigationRailAlignment;
+ field public static final androidx.compose.material3.adaptive.NavigationSuiteDefaults INSTANCE;
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public final class NavigationSuiteItemColors {
+ method public androidx.compose.material3.NavigationBarItemColors getNavigationBarItemColors();
+ method public androidx.compose.material3.NavigationDrawerItemColors getNavigationDrawerItemColors();
+ method public androidx.compose.material3.NavigationRailItemColors getNavigationRailItemColors();
+ property public final androidx.compose.material3.NavigationBarItemColors navigationBarItemColors;
+ property public final androidx.compose.material3.NavigationDrawerItemColors navigationDrawerItemColors;
+ property public final androidx.compose.material3.NavigationRailItemColors navigationRailItemColors;
+ }
+
+ public final class NavigationSuiteScaffoldKt {
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuite(androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope, optional androidx.compose.ui.Modifier modifier, optional String layoutType, optional androidx.compose.material3.adaptive.NavigationSuiteColors colors, kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScope,kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @androidx.compose.runtime.Composable public static void NavigationSuiteScaffold(kotlin.jvm.functions.Function1<? super androidx.compose.material3.adaptive.NavigationSuiteScaffoldScope,kotlin.Unit> navigationSuite, optional androidx.compose.ui.Modifier modifier, optional long containerColor, optional long contentColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScaffoldScope {
+ method public androidx.compose.ui.Modifier alignment(androidx.compose.ui.Modifier, androidx.compose.material3.adaptive.NavigationSuiteAlignment alignment);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi public interface NavigationSuiteScope {
+ method public void item(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? label, optional boolean alwaysShowLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit>? badge, optional androidx.compose.material3.adaptive.NavigationSuiteItemColors? colors, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ }
+
+ @SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class NavigationSuiteType {
+ field public static final androidx.compose.material3.adaptive.NavigationSuiteType.Companion Companion;
+ }
+
+ public static final class NavigationSuiteType.Companion {
+ method public String getNavigationBar();
+ method public String getNavigationDrawer();
+ method public String getNavigationRail();
+ property public final String NavigationBar;
+ property public final String NavigationDrawer;
+ property public final String NavigationRail;
+ }
+
@SuppressCompatibility @androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi @kotlin.jvm.JvmInline public final value class PaneAdaptedValue {
field public static final androidx.compose.material3.adaptive.PaneAdaptedValue.Companion Companion;
}
diff --git a/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt
index ad6c75f..92fdb9f 100644
--- a/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt
+++ b/compose/material3/material3-adaptive/src/androidAndroidTest/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffoldStateTest.kt
@@ -22,6 +22,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
+import kotlin.properties.Delegates
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,11 +37,13 @@
@Test
fun singlePaneLayout_navigateTo_makeFocusPaneExpanded() {
lateinit var layoutState: ListDetailPaneScaffoldState
+ var canNavigateBack by Delegates.notNull<Boolean>()
composeRule.setContent {
layoutState = rememberListDetailPaneScaffoldState(
layoutDirectives = MockSinglePaneLayoutDirective
)
+ canNavigateBack = layoutState.canNavigateBack()
}
composeRule.runOnIdle {
@@ -50,17 +53,20 @@
composeRule.runOnIdle {
assertThat(layoutState.layoutValue.secondary).isEqualTo(PaneAdaptedValue.Expanded)
+ assertThat(canNavigateBack).isTrue()
}
}
@Test
fun dualPaneLayout_navigateTo_keepFocusPaneExpanded() {
lateinit var layoutState: ListDetailPaneScaffoldState
+ var canNavigateBack by Delegates.notNull<Boolean>()
composeRule.setContent {
layoutState = rememberListDetailPaneScaffoldState(
layoutDirectives = MockDualPaneLayoutDirective
)
+ canNavigateBack = layoutState.canNavigateBack()
}
composeRule.runOnIdle {
@@ -70,28 +76,35 @@
composeRule.runOnIdle {
assertThat(layoutState.layoutValue.secondary).isEqualTo(PaneAdaptedValue.Expanded)
+ assertThat(canNavigateBack).isFalse()
}
}
@Test
fun singlePaneLayout_navigateBack_makeFocusPaneHidden() {
lateinit var layoutState: ListDetailPaneScaffoldState
+ var canNavigateBack by Delegates.notNull<Boolean>()
composeRule.setContent {
layoutState = rememberListDetailPaneScaffoldState(
layoutDirectives = MockSinglePaneLayoutDirective
)
+ canNavigateBack = layoutState.canNavigateBack()
+ }
+
+ composeRule.runOnIdle {
layoutState.navigateTo(ListDetailPaneScaffoldRole.List)
}
composeRule.runOnIdle {
assertThat(layoutState.layoutValue.secondary).isEqualTo(PaneAdaptedValue.Expanded)
- assertThat(layoutState.canNavigateBack()).isTrue()
+ assertThat(canNavigateBack).isTrue()
layoutState.navigateBack()
}
composeRule.runOnIdle {
assertThat(layoutState.layoutValue.secondary).isEqualTo(PaneAdaptedValue.Hidden)
+ assertThat(canNavigateBack).isFalse()
}
}
@@ -142,6 +155,9 @@
layoutState = rememberListDetailPaneScaffoldState(
layoutDirectives = mockCurrentLayoutDirective.value
)
+ }
+
+ composeRule.runOnIdle {
layoutState.navigateTo(ListDetailPaneScaffoldRole.List)
}
diff --git a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidWindowInfo.android.kt b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidWindowInfo.android.kt
index 786df6b..999ca64 100644
--- a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidWindowInfo.android.kt
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/AndroidWindowInfo.android.kt
@@ -45,18 +45,11 @@
* @return [WindowAdaptiveInfo] of the provided context
*/
@ExperimentalMaterial3AdaptiveApi
-@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
@Composable
fun calculateWindowAdaptiveInfo(
@UiContext context: Context = LocalContext.current
): WindowAdaptiveInfo {
- return WindowAdaptiveInfo(
- WindowSizeClass.calculateFromSize(
- windowSizeAsState(context).value.toSize(),
- LocalDensity.current
- ),
- calculatePosture(foldingFeaturesAsState(context).value)
- )
+ return context.windowAdaptiveInfo()
}
/**
@@ -112,3 +105,14 @@
}.map { it.displayFeatures.filterIsInstance<FoldingFeature>() }
}.collectAsState(emptyList())
}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3WindowSizeClassApi::class)
+@Composable
+internal fun Context.windowAdaptiveInfo() =
+ WindowAdaptiveInfo(
+ WindowSizeClass.calculateFromSize(
+ windowSizeAsState(this).value.toSize(),
+ LocalDensity.current
+ ),
+ calculatePosture(foldingFeaturesAsState(this).value)
+ )
diff --git a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt
index 57d3e56..d2b197b 100644
--- a/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/ListDetailPaneScaffold.kt
@@ -18,11 +18,14 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.Saver
+import androidx.compose.runtime.saveable.listSaver
import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
/**
@@ -124,20 +127,27 @@
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
private class DefaultListDetailPaneScaffoldState(
- override val layoutDirective: AdaptiveLayoutDirective,
- val adaptStrategies: ThreePaneScaffoldAdaptStrategies,
- val focusHistory: MutableList<ListDetailPaneScaffoldRole>
+ initialFocusHistory: List<ListDetailPaneScaffoldRole>,
+ initialLayoutDirective: AdaptiveLayoutDirective,
+ initialAdaptStrategies: ThreePaneScaffoldAdaptStrategies,
) : ListDetailPaneScaffoldState {
- val currentFocus: ListDetailPaneScaffoldRole? get() = focusHistory.lastOrNull()
- val currentValueState: MutableState<ThreePaneScaffoldValue> =
- mutableStateOf(calculateCurrentScaffoldValue())
+
+ private val focusHistory = mutableStateListOf<ListDetailPaneScaffoldRole>().apply {
+ addAll(initialFocusHistory)
+ }
+
+ override var layoutDirective by mutableStateOf(initialLayoutDirective)
+
+ var adaptStrategies by mutableStateOf(initialAdaptStrategies)
+
+ val currentFocus: ListDetailPaneScaffoldRole?
+ get() = focusHistory.lastOrNull()
override val layoutValue: ThreePaneScaffoldValue
- get() = currentValueState.value
+ get() = calculateScaffoldValue(currentFocus)
override fun navigateTo(pane: ListDetailPaneScaffoldRole) {
focusHistory.add(pane)
- currentValueState.value = calculateCurrentScaffoldValue()
}
override fun canNavigateBack(layoutValueMustChange: Boolean): Boolean =
@@ -153,7 +163,6 @@
while (focusHistory.size > targetSize) {
focusHistory.removeLast()
}
- currentValueState.value = calculateCurrentScaffoldValue()
return true
}
@@ -167,22 +176,42 @@
}
for (previousFocusIndex in focusHistory.lastIndex - 1 downTo 0) {
val newValue = calculateScaffoldValue(focusHistory[previousFocusIndex])
- if (newValue != currentValueState.value) {
+ if (newValue != layoutValue) {
return previousFocusIndex
}
}
return -1
}
- private fun calculateScaffoldValue(focus: ListDetailPaneScaffoldRole?): ThreePaneScaffoldValue =
+ private fun calculateScaffoldValue(
+ focus: ListDetailPaneScaffoldRole?
+ ): ThreePaneScaffoldValue =
calculateThreePaneScaffoldValue(
layoutDirective.maxHorizontalPartitions,
adaptStrategies,
focus?.threePaneScaffoldRole
)
- private fun calculateCurrentScaffoldValue(): ThreePaneScaffoldValue =
- calculateScaffoldValue(currentFocus)
+ companion object {
+ /**
+ * To keep focus history saved
+ */
+ fun saver(
+ initialLayoutDirective: AdaptiveLayoutDirective,
+ initialAdaptStrategies: ThreePaneScaffoldAdaptStrategies,
+ ): Saver<DefaultListDetailPaneScaffoldState, *> = listSaver(
+ save = {
+ it.focusHistory.toList()
+ },
+ restore = {
+ DefaultListDetailPaneScaffoldState(
+ initialFocusHistory = it,
+ initialLayoutDirective = initialLayoutDirective,
+ initialAdaptStrategies = initialAdaptStrategies,
+ )
+ }
+ )
+ }
}
/**
@@ -205,12 +234,22 @@
adaptStrategies: ThreePaneScaffoldAdaptStrategies =
ListDetailPaneScaffoldDefaults.adaptStrategies(),
initialFocus: ListDetailPaneScaffoldRole = ListDetailPaneScaffoldRole.Detail
-): ListDetailPaneScaffoldState {
- val focusHistory = rememberSaveable { mutableListOf(initialFocus) }
- return remember(layoutDirectives, adaptStrategies) {
- DefaultListDetailPaneScaffoldState(layoutDirectives, adaptStrategies, focusHistory)
+): ListDetailPaneScaffoldState =
+ rememberSaveable(
+ saver = DefaultListDetailPaneScaffoldState.saver(
+ layoutDirectives,
+ adaptStrategies,
+ )
+ ) {
+ DefaultListDetailPaneScaffoldState(
+ initialFocusHistory = listOf(initialFocus),
+ initialLayoutDirective = layoutDirectives,
+ initialAdaptStrategies = adaptStrategies,
+ )
+ }.apply {
+ this.layoutDirective = layoutDirectives
+ this.adaptStrategies = adaptStrategies
}
-}
/**
* The set of the available pane roles of [ListDetailPaneScaffold].
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.android.kt
similarity index 63%
copy from core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
copy to compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.android.kt
index 9914490..cbe0c48 100644
--- a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
+++ b/compose/material3/material3-adaptive/src/androidMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.android.kt
@@ -14,17 +14,12 @@
* limitations under the License.
*/
-package androidx.core.performance
+package androidx.compose.material3.adaptive
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.platform.LocalContext
-/** Unit tests for [DevicePerformance]. */
-class DevicePerformanceTest {
-
- @Test
- fun mediaPerformanceClass() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal actual val WindowAdaptiveInfoDefault: WindowAdaptiveInfo
+ @Composable
+ get() = with(LocalContext.current) { windowAdaptiveInfo() }
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuite.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuite.kt
deleted file mode 100644
index d74a22a..0000000
--- a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuite.kt
+++ /dev/null
@@ -1,630 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.material3.adaptive
-
-import androidx.compose.foundation.interaction.Interaction
-import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
-import androidx.compose.material3.BadgedBox
-import androidx.compose.material3.DrawerDefaults
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
-import androidx.compose.material3.LocalContentColor
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.NavigationBar
-import androidx.compose.material3.NavigationBarDefaults
-import androidx.compose.material3.NavigationBarItem
-import androidx.compose.material3.NavigationBarItemColors
-import androidx.compose.material3.NavigationBarItemDefaults
-import androidx.compose.material3.NavigationDrawerItem
-import androidx.compose.material3.NavigationDrawerItemColors
-import androidx.compose.material3.NavigationDrawerItemDefaults
-import androidx.compose.material3.NavigationRail
-import androidx.compose.material3.NavigationRailDefaults
-import androidx.compose.material3.NavigationRailItem
-import androidx.compose.material3.NavigationRailItemColors
-import androidx.compose.material3.NavigationRailItemDefaults
-import androidx.compose.material3.PermanentDrawerSheet
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.material3.contentColorFor
-import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion.Compact
-import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion.Expanded
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.collection.MutableVector
-import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.layout.Layout
-import androidx.compose.ui.layout.layoutId
-
-/**
- * The Navigation Suite wraps the provided content and places the adequate provided navigation
- * component on the screen according to the current [NavigationLayoutType].
- *
- * @param adaptiveInfo the current [WindowAdaptiveInfo]
- * @param modifier the [Modifier] to be applied to the navigation suite
- * @param layoutTypeProvider the current [NavigationLayoutTypeProvider]
- * @param navigationComponent the navigation component to be displayed, typically
- * [NavigationSuiteComponent]
- * @param containerColor the color used for the background of the navigation suite. Use
- * [Color.Transparent] to have no color
- * @param contentColor the preferred color for content inside the navigation suite. Defaults to
- * either the matching content color for [containerColor], or to the current [LocalContentColor] if
- * [containerColor] is not a color from the theme
- * @param content the content of your screen
- *
- * TODO: Remove "internal".
- */
-@ExperimentalMaterial3AdaptiveApi
-@Composable
-internal fun NavigationSuite(
- adaptiveInfo: WindowAdaptiveInfo,
- modifier: Modifier = Modifier,
- layoutTypeProvider: NavigationLayoutTypeProvider = NavigationSuiteDefaults.layoutTypeProvider,
- navigationComponent: @Composable () -> Unit,
- containerColor: Color = MaterialTheme.colorScheme.background,
- contentColor: Color = contentColorFor(containerColor),
- content: @Composable () -> Unit = {},
-) {
- Surface(modifier = modifier, color = containerColor, contentColor = contentColor) {
- NavigationSuiteLayout(
- navigationLayoutType = layoutTypeProvider.calculateFromAdaptiveInfo(adaptiveInfo),
- navigationComponent = navigationComponent,
- content = content
- )
- }
-}
-
-/**
- * Layout for a [NavigationSuite]'s content.
- *
- * @param navigationLayoutType the current [NavigationLayoutType] of the [NavigationSuite]
- * @param navigationComponent the navigation component of the [NavigationSuite]
- * @param content the main body of the [NavigationSuite]
- */
-@OptIn(ExperimentalMaterial3AdaptiveApi::class)
-@Composable
-private fun NavigationSuiteLayout(
- navigationLayoutType: NavigationLayoutType,
- navigationComponent: @Composable () -> Unit,
- content: @Composable () -> Unit = {}
-) {
- Layout(
- content = {
- Box(modifier = Modifier.layoutId("navigation")) { navigationComponent() }
- Box(modifier = Modifier.layoutId("content")) { content() }
- }
- ) { measurables, constraints ->
- val navigationPlaceable =
- measurables.first { it.layoutId == "navigation" }.measure(constraints)
- val layoutHeight = constraints.maxHeight
- val layoutWidth = constraints.maxWidth
- val contentPlaceable = measurables.first { it.layoutId == "content" }.measure(
- if (navigationLayoutType.orientation
- == NavigationSuiteFeature.Orientation.Horizontal
- ) {
- constraints.copy(
- minHeight = layoutHeight - navigationPlaceable.height,
- maxHeight = layoutHeight - navigationPlaceable.height
- )
- } else {
- constraints.copy(
- minWidth = layoutWidth - navigationPlaceable.width,
- maxWidth = layoutWidth - navigationPlaceable.width
- )
- }
- )
-
- layout(layoutWidth, layoutHeight) {
- when (navigationLayoutType.alignment) {
- // The navigation component can be vertical or horizontal.
- Alignment.TopStart -> {
- // Place the navigation component at the start of the screen.
- navigationPlaceable.placeRelative(0, 0)
-
- if (navigationLayoutType.orientation
- == NavigationSuiteFeature.Orientation.Horizontal
- ) {
- // Place content below the navigation component.
- contentPlaceable.placeRelative(0, navigationPlaceable.height)
- } else {
- // Place content to the side of the navigation component.
- contentPlaceable.placeRelative(navigationPlaceable.width, 0)
- }
- }
-
- // The navigation component can only be vertical.
- Alignment.TopEnd -> {
- navigationPlaceable.placeRelative(layoutWidth - navigationPlaceable.width, 0)
- // Place content at the start of the screen.
- contentPlaceable.placeRelative(0, 0)
- }
-
- // The navigation component can only be horizontal.
- Alignment.BottomStart -> {
- // Place content above the navigation component.
- contentPlaceable.placeRelative(0, 0)
- // Place the navigation component at the bottom of the screen.
- navigationPlaceable.placeRelative(0, layoutHeight - navigationPlaceable.height)
- }
-
- else -> {
- // Do nothing if it's not a supported [Alignment].
- }
- }
- }
- }
-}
-
-/**
- * The default Material navigation component according to the current [NavigationLayoutType] to be
- * used with the Navigation Suite.
- *
- * For specifics about each navigation component, see [NavigationBar], [NavigationRail], and
- * [PermanentDrawerSheet].
- *
- * @param adaptiveInfo the current [WindowAdaptiveInfo] of the [NavigationSuite]
- * @param modifier the [Modifier] to be applied to the navigation component
- * @params colors [NavigationSuiteColors] that will be used to determine the container (background)
- * color of the navigation component and the preferred color for content inside the navigation
- * component
- * @param layoutTypeProvider the current [NavigationLayoutTypeProvider] of the [NavigationSuite]
- * @param content the content inside the current navigation component, typically
- * [NavigationSuiteComponentScope.item]s
- *
- * TODO: Remove "internal".
- */
-@OptIn(ExperimentalMaterial3AdaptiveApi::class)
-@Composable
-internal fun NavigationSuiteComponent(
- adaptiveInfo: WindowAdaptiveInfo,
- modifier: Modifier = Modifier,
- layoutTypeProvider: NavigationLayoutTypeProvider = NavigationSuiteDefaults.layoutTypeProvider,
- colors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
- content: NavigationSuiteComponentScope.() -> Unit
-) {
- val scope by rememberStateOfItems(content)
-
- when (layoutTypeProvider.calculateFromAdaptiveInfo(adaptiveInfo)) {
- NavigationLayoutType.NavigationBar -> {
- NavigationBar(
- modifier = modifier,
- containerColor = colors.navigationBarContainerColor,
- contentColor = colors.navigationBarContentColor
- ) {
- scope.itemList.forEach {
- NavigationBarItem(
- modifier = it.modifier,
- selected = it.selected,
- onClick = it.onClick,
- icon = { NavigationItemIcon(icon = it.icon, badge = it.badge) },
- enabled = it.enabled,
- label = it.label,
- alwaysShowLabel = it.alwaysShowLabel,
- colors = it.colors?.navigationBarItemColors
- ?: NavigationBarItemDefaults.colors(),
- interactionSource = it.interactionSource
- )
- }
- }
- }
-
- NavigationLayoutType.NavigationRail -> {
- NavigationRail(
- modifier = modifier,
- containerColor = colors.navigationRailContainerColor,
- contentColor = colors.navigationRailContentColor
- ) {
- scope.itemList.forEach {
- NavigationRailItem(
- modifier = it.modifier,
- selected = it.selected,
- onClick = it.onClick,
- icon = { NavigationItemIcon(icon = it.icon, badge = it.badge) },
- enabled = it.enabled,
- label = it.label,
- alwaysShowLabel = it.alwaysShowLabel,
- colors = it.colors?.navigationRailItemColors
- ?: NavigationRailItemDefaults.colors(),
- interactionSource = it.interactionSource
- )
- }
- }
- }
-
- NavigationLayoutType.NavigationDrawer -> {
- PermanentDrawerSheet(
- modifier = modifier,
- drawerContainerColor = colors.navigationDrawerContainerColor,
- drawerContentColor = colors.navigationDrawerContentColor
- ) {
- scope.itemList.forEach {
- NavigationDrawerItem(
- modifier = it.modifier,
- selected = it.selected,
- onClick = it.onClick,
- icon = it.icon,
- badge = it.badge,
- label = { it.label?.invoke() ?: Text("") },
- colors = it.colors?.navigationDrawerItemColors
- ?: NavigationDrawerItemDefaults.colors(),
- interactionSource = it.interactionSource
- )
- }
- }
- }
- }
-}
-
-/**
- * A feature that describes characteristics of the navigation component of the [NavigationSuite].
- *
- * TODO: Remove "internal".
- */
-@ExperimentalMaterial3AdaptiveApi
-internal interface NavigationSuiteFeature {
- /**
- * Represents the orientation of the navigation component of the [NavigationSuite].
- */
- enum class Orientation {
- /**
- * The navigation component of the [NavigationSuite] is horizontal, such as the
- * Navigation Bar.
- */
- Horizontal,
-
- /**
- * The navigation component of the [NavigationSuite] is vertical, such as the
- * Navigation Rail or Navigation Drawer.
- */
- Vertical
- }
-}
-
-/**
- * Class that describes the different navigation layout types of the [NavigationSuite].
- *
- * The [NavigationLayoutType] informs the [NavigationSuite] of what navigation component to expect
- * and how to properly place it on the screen in relation to the [NavigationSuite]'s content.
- *
- * @param description the description of the [NavigationLayoutType]
- * @param alignment the [Alignment] of the [NavigationLayoutType] that helps inform how the
- * navigation component will be positioned on the screen. The current supported alignments are:
- * [Alignment.TopStart], [Alignment.BottomStart], and [Alignment.TopEnd]
- * @param orientation the [NavigationSuiteFeature.Orientation] of the [NavigationLayoutType] that
- * helps inform how the navigation component will be positioned on the screen in relation to the
- * content
- *
- * TODO: Make class open instead of internal.
- */
-@ExperimentalMaterial3AdaptiveApi
-internal class NavigationLayoutType constructor(
- private val description: String,
- // TODO: Make this an internal open val.
- internal val alignment: Alignment,
- // TODO: Make this an internal open val.
- internal val orientation: NavigationSuiteFeature.Orientation
-) {
- override fun toString(): String {
- return description
- }
-
- companion object {
- /**
- * A navigation layout type that instructs the [NavigationSuite] to expect a [NavigationBar]
- * and properly place it on the screen.
- *
- * @see NavigationBar
- */
- @JvmField
- val NavigationBar =
- NavigationLayoutType(
- description = "NavigationBar",
- alignment = Alignment.BottomStart,
- orientation = NavigationSuiteFeature.Orientation.Horizontal,
- )
-
- /**
- * A navigation layout type that instructs the [NavigationSuite] to expect a
- * [NavigationRail] and properly place it on the screen.
- *
- * @see NavigationRail
- */
- @JvmField
- val NavigationRail =
- NavigationLayoutType(
- description = "NavigationRail",
- alignment = Alignment.TopStart,
- orientation = NavigationSuiteFeature.Orientation.Vertical,
- )
-
- /**
- * A navigation layout type that instructs the [NavigationSuite] to expect a
- * [PermanentDrawerSheet] and properly place it on the screen.
- *
- * @see PermanentDrawerSheet
- */
- @JvmField
- val NavigationDrawer =
- NavigationLayoutType(
- description = "NavigationDrawer",
- alignment = Alignment.TopStart,
- orientation = NavigationSuiteFeature.Orientation.Vertical,
- )
- }
-}
-
-/**
- * The scope associated with the [NavigationSuiteComponent].
- *
- * TODO: Remove "internal".
- */
-internal interface NavigationSuiteComponentScope {
-
- /**
- * This function sets the parameters of the default Material navigation item to be used with the
- * Navigation Suite. The item is called in [NavigationSuiteComponent], according to the current
- * [NavigationLayoutType].
- *
- * For specifics about each item component, see [NavigationBarItem], [NavigationRailItem], and
- * [NavigationDrawerItem].
- *
- * @param selected whether this item is selected
- * @param onClick called when this item is clicked
- * @param icon icon for this item, typically an [Icon]
- * @param modifier the [Modifier] to be applied to this item
- * @param enabled controls the enabled state of this item. When `false`, this component will not
- * respond to user input, and it will appear visually disabled and disabled to accessibility
- * services. Note: as of now, for [NavigationDrawerItem], this is always `true`.
- * @param label the text label for this item
- * @param alwaysShowLabel whether to always show the label for this item. If `false`, the label will
- * only be shown when this item is selected. Note: for [NavigationDrawerItem] this is always `true`
- * @param badge optional badge to show on this item
- * @param colors [NavigationSuiteItemColors] that will be used to resolve the colors used for this
- * item in different states.
- * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
- * for this item. You can create and pass in your own `remember`ed instance to observe
- * [Interaction]s and customize the appearance / behavior of this item in different states
- */
- fun item(
- selected: Boolean,
- onClick: () -> Unit,
- icon: @Composable () -> Unit,
- modifier: Modifier = Modifier,
- enabled: Boolean = true,
- label: @Composable (() -> Unit)? = null,
- alwaysShowLabel: Boolean = true,
- badge: (@Composable () -> Unit)? = null,
- colors: NavigationSuiteItemColors? = null,
- interactionSource: MutableInteractionSource = MutableInteractionSource()
- )
-}
-
-/**
- * A [NavigationLayoutType] provider associated with the [NavigationSuite] and the
- * [NavigationSuiteComponent].
- *
- * TODO: Remove "internal".
- */
-internal fun interface NavigationLayoutTypeProvider {
-
- /**
- * Returns the expected [NavigationLayoutType] according to the provided
- * [WindowAdaptiveInfo].
- *
- * @param adaptiveInfo the provided [WindowAdaptiveInfo]
- */
- @OptIn(ExperimentalMaterial3AdaptiveApi::class)
- fun calculateFromAdaptiveInfo(adaptiveInfo: WindowAdaptiveInfo): NavigationLayoutType
-}
-
-/**
- * Contains the default values used by the [NavigationSuite].
- *
- * TODO: Remove "internal".
- */
-@OptIn(ExperimentalMaterial3AdaptiveApi::class)
-internal object NavigationSuiteDefaults {
-
- /** The default implementation of the [NavigationLayoutTypeProvider]. */
- val layoutTypeProvider = NavigationLayoutTypeProvider { adaptiveInfo ->
- with(adaptiveInfo) {
- if (posture.isTabletop || windowSizeClass.heightSizeClass == Compact) {
- NavigationLayoutType.NavigationBar
- } else if (windowSizeClass.widthSizeClass == Expanded) {
- NavigationLayoutType.NavigationRail
- } else {
- NavigationLayoutType.NavigationBar
- }
- }
- }
-
- /**
- * Creates a [NavigationSuiteColors] with the provided colors for the container color, according
- * to the Material specification.
- *
- * Use [Color.Transparent] for the navigation*ContainerColor to have no color. The
- * navigation*ContentColor will default to either the matching content color for
- * navigation*ContainerColor, or to the current [LocalContentColor] if navigation*ContainerColor
- * is not a color from the theme.
- *
- * @param navigationBarContainerColor the default container color for the [NavigationBar]
- * @param navigationBarContentColor the default content color for the [NavigationBar]
- * @param navigationRailContainerColor the default container color for the [NavigationRail]
- * @param navigationRailContentColor the default content color for the [NavigationRail]
- * @param navigationDrawerContainerColor the default container color for the
- * [PermanentDrawerSheet]
- * @param navigationDrawerContentColor the default content color for the [PermanentDrawerSheet]
- */
- @Composable
- fun colors(
- navigationBarContainerColor: Color = NavigationBarDefaults.containerColor,
- navigationBarContentColor: Color = contentColorFor(navigationBarContainerColor),
- navigationRailContainerColor: Color = NavigationRailDefaults.ContainerColor,
- navigationRailContentColor: Color = contentColorFor(navigationRailContainerColor),
- navigationDrawerContainerColor: Color = DrawerDefaults.containerColor,
- navigationDrawerContentColor: Color = contentColorFor(navigationDrawerContainerColor),
- ): NavigationSuiteColors =
- NavigationSuiteColors(
- navigationBarContainerColor = navigationBarContainerColor,
- navigationBarContentColor = navigationBarContentColor,
- navigationRailContainerColor = navigationRailContainerColor,
- navigationRailContentColor = navigationRailContentColor,
- navigationDrawerContainerColor = navigationDrawerContainerColor,
- navigationDrawerContentColor = navigationDrawerContentColor
- )
-}
-
-/**
- * Represents the colors of a [NavigationSuiteComponent].
- *
- * For specifics about each navigation component colors see [NavigationBarDefaults],
- * [NavigationRailDefaults], and [DrawerDefaults].
- *
- * @param navigationBarContainerColor the container color for the [NavigationBar] of the
- * [NavigationSuiteComponent]
- * @param navigationBarContentColor the content color for the [NavigationBar] of the
- * [NavigationSuiteComponent]
- * @param navigationRailContainerColor the container color for the [NavigationRail] of the
- * [NavigationSuiteComponent]
- * @param navigationRailContentColor the content color for the [NavigationRail] of the
- * [NavigationSuiteComponent]
- * @param navigationDrawerContainerColor the container color for the [PermanentDrawerSheet] of the
- * [NavigationSuiteComponent]
- * @param navigationDrawerContentColor the content color for the [PermanentDrawerSheet] of the
- * [NavigationSuiteComponent]
- *
- * TODO: Remove "internal".
- */
-internal class NavigationSuiteColors
-internal constructor(
- val navigationBarContainerColor: Color,
- val navigationBarContentColor: Color,
- val navigationRailContainerColor: Color,
- val navigationRailContentColor: Color,
- val navigationDrawerContainerColor: Color,
- val navigationDrawerContentColor: Color
-)
-
-/**
- * Represents the colors of a [NavigationSuiteComponentScope.item].
- *
- * For specifics about each navigation item colors see [NavigationBarItemColors],
- * [NavigationRailItemColors], and [NavigationDrawerItemColors].
- *
- * @param navigationBarItemColors the [NavigationBarItemColors] associated with the
- * [NavigationBarItem] of the [NavigationSuiteComponentScope.item]
- * @param navigationRailItemColors the [NavigationRailItemColors] associated with the
- * [NavigationRailItem] of the [NavigationSuiteComponentScope.item]
- * @param navigationDrawerItemColors the [NavigationDrawerItemColors] associated with the
- * [NavigationDrawerItem] of the [NavigationSuiteComponentScope.item]
- *
- * TODO: Remove "internal".
- */
-internal class NavigationSuiteItemColors
-internal constructor(
- val navigationBarItemColors: NavigationBarItemColors,
- val navigationRailItemColors: NavigationRailItemColors,
- val navigationDrawerItemColors: NavigationDrawerItemColors,
-)
-
-private interface NavigationSuiteItemProvider {
- val itemsCount: Int
- val itemList: MutableVector<NavigationSuiteItem>
-}
-
-private class NavigationSuiteItem(
- val selected: Boolean,
- val onClick: () -> Unit,
- val icon: @Composable () -> Unit,
- val modifier: Modifier,
- val enabled: Boolean,
- val label: @Composable (() -> Unit)?,
- val alwaysShowLabel: Boolean,
- val badge: (@Composable () -> Unit)?,
- val colors: NavigationSuiteItemColors?,
- val interactionSource: MutableInteractionSource
-)
-
-private class NavigationSuiteComponentScopeImpl : NavigationSuiteComponentScope,
- NavigationSuiteItemProvider {
-
- override fun item(
- selected: Boolean,
- onClick: () -> Unit,
- icon: @Composable () -> Unit,
- modifier: Modifier,
- enabled: Boolean,
- label: @Composable (() -> Unit)?,
- alwaysShowLabel: Boolean,
- badge: (@Composable () -> Unit)?,
- colors: NavigationSuiteItemColors?,
- interactionSource: MutableInteractionSource
- ) {
- itemList.add(
- NavigationSuiteItem(
- selected = selected,
- onClick = onClick,
- icon = icon,
- modifier = modifier,
- enabled = enabled,
- label = label,
- alwaysShowLabel = alwaysShowLabel,
- badge = badge,
- colors = colors,
- interactionSource = interactionSource
- )
- )
- }
-
- override val itemList: MutableVector<NavigationSuiteItem> = mutableVectorOf()
-
- override val itemsCount: Int
- get() = itemList.size
-}
-
-@Composable
-private fun rememberStateOfItems(
- content: NavigationSuiteComponentScope.() -> Unit
-): State<NavigationSuiteItemProvider> {
- val latestContent = rememberUpdatedState(content)
- return remember {
- derivedStateOf { NavigationSuiteComponentScopeImpl().apply(latestContent.value) }
- }
-}
-
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-private fun NavigationItemIcon(
- icon: @Composable () -> Unit,
- badge: (@Composable () -> Unit)? = null,
-) {
- if (badge != null) {
- BadgedBox(badge = { badge.invoke() }) {
- icon()
- }
- } else {
- icon()
- }
-}
diff --git a/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.kt b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.kt
new file mode 100644
index 0000000..9620e34
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/commonMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.kt
@@ -0,0 +1,663 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.material3.adaptive
+
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.material3.BadgedBox
+import androidx.compose.material3.DrawerDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.LocalContentColor
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.NavigationBar
+import androidx.compose.material3.NavigationBarDefaults
+import androidx.compose.material3.NavigationBarItem
+import androidx.compose.material3.NavigationBarItemColors
+import androidx.compose.material3.NavigationBarItemDefaults
+import androidx.compose.material3.NavigationDrawerItem
+import androidx.compose.material3.NavigationDrawerItemColors
+import androidx.compose.material3.NavigationDrawerItemDefaults
+import androidx.compose.material3.NavigationRail
+import androidx.compose.material3.NavigationRailDefaults
+import androidx.compose.material3.NavigationRailItem
+import androidx.compose.material3.NavigationRailItemColors
+import androidx.compose.material3.NavigationRailItemDefaults
+import androidx.compose.material3.PermanentDrawerSheet
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.contentColorFor
+import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass.Companion.Compact
+import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass.Companion.Expanded
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.collection.MutableVector
+import androidx.compose.runtime.collection.mutableVectorOf
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.IntrinsicMeasurable
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.ParentDataModifierNode
+import androidx.compose.ui.platform.InspectorInfo
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.util.fastMap
+
+/**
+ * The Navigation Suite Scaffold wraps the provided content and places the adequate provided
+ * navigation component on the screen according to the current [NavigationSuiteType].
+ *
+ * @param navigationSuite the navigation component to be displayed, typically [NavigationSuite]
+ * @param modifier the [Modifier] to be applied to the navigation suite scaffold
+ * @param containerColor the color used for the background of the navigation suite scaffold. Use
+ * [Color.Transparent] to have no color
+ * @param contentColor the preferred color for content inside the navigation suite scaffold.
+ * Defaults to either the matching content color for [containerColor], or to the current
+ * [LocalContentColor] if [containerColor] is not a color from the theme
+ * @param content the content of your screen
+ */
+@ExperimentalMaterial3AdaptiveApi
+@Composable
+fun NavigationSuiteScaffold(
+ navigationSuite: @Composable NavigationSuiteScaffoldScope.() -> Unit,
+ modifier: Modifier = Modifier,
+ containerColor: Color = MaterialTheme.colorScheme.background,
+ contentColor: Color = contentColorFor(containerColor),
+ content: @Composable () -> Unit = {},
+) {
+ Surface(modifier = modifier, color = containerColor, contentColor = contentColor) {
+ NavigationSuiteScaffoldLayout(
+ navigationSuite = navigationSuite,
+ content = content
+ )
+ }
+}
+
+/**
+ * Layout for a [NavigationSuiteScaffold]'s content.
+ *
+ * @param navigationSuite the navigation suite of the [NavigationSuiteScaffold]
+ * @param content the main body of the [NavigationSuiteScaffold]
+ * @throws [IllegalArgumentException] if there is more than one [NavigationSuiteAlignment] for the
+ * given navigation component
+ */
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+@Composable
+private fun NavigationSuiteScaffoldLayout(
+ navigationSuite: @Composable NavigationSuiteScaffoldScope.() -> Unit,
+ content: @Composable () -> Unit = {}
+) {
+ Layout(
+ contents = listOf({ NavigationSuiteScaffoldScopeImpl.navigationSuite() }, content)
+ ) { (navigationMeasurables, contentMeasurables), constraints ->
+ val navigationPlaceables = navigationMeasurables.map { it.measure(constraints) }
+ val alignments = navigationPlaceables.fastMap {
+ (it.parentData as NavigationSuiteParentData).alignment
+ }.filterNotNull()
+ if (alignments.all { alignments[0] != it }) {
+ throw IllegalArgumentException("There should be only one NavigationSuiteAlignment.")
+ }
+ val alignment = alignments.firstOrNull() ?: NavigationSuiteAlignment.StartVertical
+ val layoutHeight = constraints.maxHeight
+ val layoutWidth = constraints.maxWidth
+ val contentPlaceables = contentMeasurables.map { it.measure(
+ if (alignment == NavigationSuiteAlignment.TopHorizontal ||
+ alignment == NavigationSuiteAlignment.BottomHorizontal
+ ) {
+ constraints.copy(
+ minHeight = layoutHeight - navigationPlaceables.maxOf { it.height },
+ maxHeight = layoutHeight - navigationPlaceables.maxOf { it.height }
+ )
+ } else {
+ constraints.copy(
+ minWidth = layoutWidth - navigationPlaceables.maxOf { it.width },
+ maxWidth = layoutWidth - navigationPlaceables.maxOf { it.width }
+ )
+ }
+ ) }
+
+ layout(layoutWidth, layoutHeight) {
+ when (alignment) {
+ NavigationSuiteAlignment.StartVertical -> {
+ // Place the navigation component at the start of the screen.
+ navigationPlaceables.forEach {
+ it.placeRelative(0, 0)
+ }
+ // Place content to the side of the navigation component.
+ contentPlaceables.forEach {
+ it.placeRelative(navigationPlaceables.maxOf { it.width }, 0)
+ }
+ }
+
+ NavigationSuiteAlignment.EndVertical -> {
+ // Place the navigation component at the end of the screen.
+ navigationPlaceables.forEach {
+ it.placeRelative(
+ layoutWidth - navigationPlaceables.maxOf { it.width },
+ 0
+ )
+ }
+ // Place content at the start of the screen.
+ contentPlaceables.forEach {
+ it.placeRelative(0, 0)
+ }
+ }
+
+ NavigationSuiteAlignment.TopHorizontal -> {
+ // Place the navigation component at the start of the screen.
+ navigationPlaceables.forEach {
+ it.placeRelative(0, 0)
+ }
+ // Place content below the navigation component.
+ contentPlaceables.forEach {
+ it.placeRelative(0, navigationPlaceables.maxOf { it.height })
+ }
+ }
+
+ NavigationSuiteAlignment.BottomHorizontal -> {
+ // Place content above the navigation component.
+ contentPlaceables.forEach {
+ it.placeRelative(0, 0)
+ }
+ // Place the navigation component at the bottom of the screen.
+ navigationPlaceables.forEach {
+ it.placeRelative(
+ 0,
+ layoutHeight - navigationPlaceables.maxOf { it.height })
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * The default Material navigation component according to the current [NavigationSuiteType] to be
+ * used with the [NavigationSuiteScaffold].
+ *
+ * For specifics about each navigation component, see [NavigationBar], [NavigationRail], and
+ * [PermanentDrawerSheet].
+ *
+ * @param modifier the [Modifier] to be applied to the navigation component
+ * @param layoutType the current [NavigationSuiteType] of the [NavigationSuiteScaffold]. Defaults to
+ * [NavigationSuiteDefaults.calculateFromAdaptiveInfo]
+ * @param colors [NavigationSuiteColors] that will be used to determine the container (background)
+ * color of the navigation component and the preferred color for content inside the navigation
+ * component
+ * @param content the content inside the current navigation component, typically
+ * [NavigationSuiteScope.item]s
+ */
+@ExperimentalMaterial3AdaptiveApi
+@Composable
+fun NavigationSuiteScaffoldScope.NavigationSuite(
+ modifier: Modifier = Modifier,
+ layoutType: NavigationSuiteType =
+ NavigationSuiteDefaults.calculateFromAdaptiveInfo(WindowAdaptiveInfoDefault),
+ colors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
+ content: NavigationSuiteScope.() -> Unit
+) {
+ val scope by rememberStateOfItems(content)
+
+ when (layoutType) {
+ NavigationSuiteType.NavigationBar -> {
+ NavigationBar(
+ modifier = modifier.alignment(NavigationSuiteDefaults.NavigationBarAlignment),
+ containerColor = colors.navigationBarContainerColor,
+ contentColor = colors.navigationBarContentColor
+ ) {
+ scope.itemList.forEach {
+ NavigationBarItem(
+ modifier = it.modifier,
+ selected = it.selected,
+ onClick = it.onClick,
+ icon = { NavigationItemIcon(icon = it.icon, badge = it.badge) },
+ enabled = it.enabled,
+ label = it.label,
+ alwaysShowLabel = it.alwaysShowLabel,
+ colors = it.colors?.navigationBarItemColors
+ ?: NavigationBarItemDefaults.colors(),
+ interactionSource = it.interactionSource
+ )
+ }
+ }
+ }
+
+ NavigationSuiteType.NavigationRail -> {
+ NavigationRail(
+ modifier = modifier.alignment(NavigationSuiteDefaults.NavigationRailAlignment),
+ containerColor = colors.navigationRailContainerColor,
+ contentColor = colors.navigationRailContentColor
+ ) {
+ scope.itemList.forEach {
+ NavigationRailItem(
+ modifier = it.modifier,
+ selected = it.selected,
+ onClick = it.onClick,
+ icon = { NavigationItemIcon(icon = it.icon, badge = it.badge) },
+ enabled = it.enabled,
+ label = it.label,
+ alwaysShowLabel = it.alwaysShowLabel,
+ colors = it.colors?.navigationRailItemColors
+ ?: NavigationRailItemDefaults.colors(),
+ interactionSource = it.interactionSource
+ )
+ }
+ }
+ }
+
+ NavigationSuiteType.NavigationDrawer -> {
+ PermanentDrawerSheet(
+ modifier = modifier.alignment(NavigationSuiteDefaults.NavigationDrawerAlignment),
+ drawerContainerColor = colors.navigationDrawerContainerColor,
+ drawerContentColor = colors.navigationDrawerContentColor
+ ) {
+ scope.itemList.forEach {
+ NavigationDrawerItem(
+ modifier = it.modifier,
+ selected = it.selected,
+ onClick = it.onClick,
+ icon = it.icon,
+ badge = it.badge,
+ label = { it.label?.invoke() ?: Text("") },
+ colors = it.colors?.navigationDrawerItemColors
+ ?: NavigationDrawerItemDefaults.colors(),
+ interactionSource = it.interactionSource
+ )
+ }
+ }
+ }
+ }
+}
+
+/** The scope associated with the [NavigationSuiteScaffold]. */
+@ExperimentalMaterial3AdaptiveApi
+interface NavigationSuiteScaffoldScope {
+ /**
+ * [Modifier] that should be applied to the [NavigationSuite] of the [NavigationSuiteScaffold]
+ * in order to determine its alignment on the screen.
+ *
+ * @param alignment the desired [NavigationSuiteAlignment]
+ */
+ fun Modifier.alignment(alignment: NavigationSuiteAlignment): Modifier
+}
+
+/**
+ * Represents the alignment of the navigation component of the [NavigationSuiteScaffold].
+ *
+ * The alignment informs the Navigation Suite Scaffold how to properly place the expected navigation
+ * component on the screen in relation to the Navigation Suite Scaffold's content.
+ */
+@ExperimentalMaterial3AdaptiveApi
+enum class NavigationSuiteAlignment {
+ /** The navigation component is vertical and positioned at the start of the screen. */
+ StartVertical,
+ /** The navigation component is vertical and positioned at the end of the screen. */
+ EndVertical,
+ /** The navigation component is horizontal and positioned at the top of the screen. */
+ TopHorizontal,
+ /** The navigation component is horizontal and positioned at the bottom of the screen. */
+ BottomHorizontal
+}
+
+/** The scope associated with the [NavigationSuite]. */
+@ExperimentalMaterial3AdaptiveApi
+interface NavigationSuiteScope {
+
+ /**
+ * This function sets the parameters of the default Material navigation item to be used with the
+ * Navigation Suite Scaffold. The item is called in [NavigationSuite], according to the
+ * current [NavigationSuiteType].
+ *
+ * For specifics about each item component, see [NavigationBarItem], [NavigationRailItem], and
+ * [NavigationDrawerItem].
+ *
+ * @param selected whether this item is selected
+ * @param onClick called when this item is clicked
+ * @param icon icon for this item, typically an [Icon]
+ * @param modifier the [Modifier] to be applied to this item
+ * @param enabled controls the enabled state of this item. When `false`, this component will not
+ * respond to user input, and it will appear visually disabled and disabled to accessibility
+ * services. Note: as of now, for [NavigationDrawerItem], this is always `true`.
+ * @param label the text label for this item
+ * @param alwaysShowLabel whether to always show the label for this item. If `false`, the label will
+ * only be shown when this item is selected. Note: for [NavigationDrawerItem] this is always `true`
+ * @param badge optional badge to show on this item
+ * @param colors [NavigationSuiteItemColors] that will be used to resolve the colors used for this
+ * item in different states.
+ * @param interactionSource the [MutableInteractionSource] representing the stream of [Interaction]s
+ * for this item. You can create and pass in your own `remember`ed instance to observe
+ * [Interaction]s and customize the appearance / behavior of this item in different states
+ */
+ fun item(
+ selected: Boolean,
+ onClick: () -> Unit,
+ icon: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ label: @Composable (() -> Unit)? = null,
+ alwaysShowLabel: Boolean = true,
+ badge: (@Composable () -> Unit)? = null,
+ colors: NavigationSuiteItemColors? = null,
+ interactionSource: MutableInteractionSource = MutableInteractionSource()
+ )
+}
+
+/**
+ * Class that describes the different navigation suite types of the [NavigationSuiteScaffold].
+ *
+ * The [NavigationSuiteType] informs the [NavigationSuite] of what navigation component to expect.
+ */
+@JvmInline
+@ExperimentalMaterial3AdaptiveApi
+value class NavigationSuiteType private constructor(private val description: String) {
+ override fun toString(): String {
+ return description
+ }
+
+ companion object {
+ /**
+ * A navigation suite type that instructs the [NavigationSuite] to expect a [NavigationBar].
+ *
+ * @see NavigationBar
+ */
+ val NavigationBar = NavigationSuiteType(description = "NavigationBar")
+
+ /**
+ * A navigation suite type that instructs the [NavigationSuite] to expect a
+ * [NavigationRail].
+ *
+ * @see NavigationRail
+ */
+ val NavigationRail = NavigationSuiteType(description = "NavigationRail")
+
+ /**
+ * A navigation suite type that instructs the [NavigationSuite] to expect a
+ * [PermanentDrawerSheet].
+ *
+ * @see PermanentDrawerSheet
+ */
+ val NavigationDrawer = NavigationSuiteType(description = "NavigationDrawer")
+ }
+}
+
+/** Contains the default values used by the [NavigationSuite]. */
+@ExperimentalMaterial3AdaptiveApi
+object NavigationSuiteDefaults {
+ /**
+ * Returns the expected [NavigationSuiteType] according to the provided [WindowAdaptiveInfo].
+ * Usually used with the [NavigationSuite].
+ *
+ * @param adaptiveInfo the provided [WindowAdaptiveInfo]
+ * @see NavigationSuite
+ */
+ fun calculateFromAdaptiveInfo(adaptiveInfo: WindowAdaptiveInfo): NavigationSuiteType {
+ return with(adaptiveInfo) {
+ if (posture.isTabletop || windowSizeClass.heightSizeClass == Compact) {
+ NavigationSuiteType.NavigationBar
+ } else if (windowSizeClass.widthSizeClass == Expanded) {
+ NavigationSuiteType.NavigationRail
+ } else {
+ NavigationSuiteType.NavigationBar
+ }
+ }
+ }
+
+ /** Default alignment for the [NavigationSuiteType.NavigationBar]. */
+ val NavigationBarAlignment = NavigationSuiteAlignment.BottomHorizontal
+
+ /** Default alignment for the [NavigationSuiteType.NavigationRail]. */
+ val NavigationRailAlignment = NavigationSuiteAlignment.StartVertical
+
+ /** Default alignment for the [NavigationSuiteType.NavigationDrawer]. */
+ val NavigationDrawerAlignment = NavigationSuiteAlignment.StartVertical
+
+ /**
+ * Creates a [NavigationSuiteColors] with the provided colors for the container color, according
+ * to the Material specification.
+ *
+ * Use [Color.Transparent] for the navigation*ContainerColor to have no color. The
+ * navigation*ContentColor will default to either the matching content color for
+ * navigation*ContainerColor, or to the current [LocalContentColor] if navigation*ContainerColor
+ * is not a color from the theme.
+ *
+ * @param navigationBarContainerColor the default container color for the [NavigationBar]
+ * @param navigationBarContentColor the default content color for the [NavigationBar]
+ * @param navigationRailContainerColor the default container color for the [NavigationRail]
+ * @param navigationRailContentColor the default content color for the [NavigationRail]
+ * @param navigationDrawerContainerColor the default container color for the
+ * [PermanentDrawerSheet]
+ * @param navigationDrawerContentColor the default content color for the [PermanentDrawerSheet]
+ */
+ @Composable
+ fun colors(
+ navigationBarContainerColor: Color = NavigationBarDefaults.containerColor,
+ navigationBarContentColor: Color = contentColorFor(navigationBarContainerColor),
+ navigationRailContainerColor: Color = NavigationRailDefaults.ContainerColor,
+ navigationRailContentColor: Color = contentColorFor(navigationRailContainerColor),
+ navigationDrawerContainerColor: Color = DrawerDefaults.containerColor,
+ navigationDrawerContentColor: Color = contentColorFor(navigationDrawerContainerColor),
+ ): NavigationSuiteColors =
+ NavigationSuiteColors(
+ navigationBarContainerColor = navigationBarContainerColor,
+ navigationBarContentColor = navigationBarContentColor,
+ navigationRailContainerColor = navigationRailContainerColor,
+ navigationRailContentColor = navigationRailContentColor,
+ navigationDrawerContainerColor = navigationDrawerContainerColor,
+ navigationDrawerContentColor = navigationDrawerContentColor
+ )
+}
+
+/**
+ * Represents the colors of a [NavigationSuite].
+ *
+ * For specifics about each navigation component colors see [NavigationBarDefaults],
+ * [NavigationRailDefaults], and [DrawerDefaults].
+ *
+ * @param navigationBarContainerColor the container color for the [NavigationBar] of the
+ * [NavigationSuite]
+ * @param navigationBarContentColor the content color for the [NavigationBar] of the
+ * [NavigationSuite]
+ * @param navigationRailContainerColor the container color for the [NavigationRail] of the
+ * [NavigationSuite]
+ * @param navigationRailContentColor the content color for the [NavigationRail] of the
+ * [NavigationSuite]
+ * @param navigationDrawerContainerColor the container color for the [PermanentDrawerSheet] of the
+ * [NavigationSuite]
+ * @param navigationDrawerContentColor the content color for the [PermanentDrawerSheet] of the
+ * [NavigationSuite]
+ */
+@ExperimentalMaterial3AdaptiveApi
+class NavigationSuiteColors
+internal constructor(
+ val navigationBarContainerColor: Color,
+ val navigationBarContentColor: Color,
+ val navigationRailContainerColor: Color,
+ val navigationRailContentColor: Color,
+ val navigationDrawerContainerColor: Color,
+ val navigationDrawerContentColor: Color
+)
+
+/**
+ * Represents the colors of a [NavigationSuiteScope.item].
+ *
+ * For specifics about each navigation item colors see [NavigationBarItemColors],
+ * [NavigationRailItemColors], and [NavigationDrawerItemColors].
+ *
+ * @param navigationBarItemColors the [NavigationBarItemColors] associated with the
+ * [NavigationBarItem] of the [NavigationSuiteScope.item]
+ * @param navigationRailItemColors the [NavigationRailItemColors] associated with the
+ * [NavigationRailItem] of the [NavigationSuiteScope.item]
+ * @param navigationDrawerItemColors the [NavigationDrawerItemColors] associated with the
+ * [NavigationDrawerItem] of the [NavigationSuiteScope.item]
+ */
+@ExperimentalMaterial3AdaptiveApi
+class NavigationSuiteItemColors
+internal constructor(
+ val navigationBarItemColors: NavigationBarItemColors,
+ val navigationRailItemColors: NavigationRailItemColors,
+ val navigationDrawerItemColors: NavigationDrawerItemColors,
+)
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal object NavigationSuiteScaffoldScopeImpl : NavigationSuiteScaffoldScope {
+ override fun Modifier.alignment(alignment: NavigationSuiteAlignment): Modifier {
+ return this.then(
+ AlignmentElement(alignment = alignment)
+ )
+ }
+}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal class AlignmentElement(
+ val alignment: NavigationSuiteAlignment
+) : ModifierNodeElement<AlignmentNode>() {
+ override fun create(): AlignmentNode {
+ return AlignmentNode(alignment)
+ }
+
+ override fun update(node: AlignmentNode) {
+ node.alignment = alignment
+ }
+
+ override fun InspectorInfo.inspectableProperties() {
+ name = "alignment"
+ value = alignment
+ }
+
+ override fun hashCode(): Int = alignment.hashCode()
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ val otherModifier = other as? AlignmentElement ?: return false
+ return alignment == otherModifier.alignment
+ }
+}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal class AlignmentNode(
+ var alignment: NavigationSuiteAlignment
+) : ParentDataModifierNode, Modifier.Node() {
+ override fun Density.modifyParentData(parentData: Any?) =
+ ((parentData as? NavigationSuiteParentData) ?: NavigationSuiteParentData()).also {
+ it.alignment = alignment
+ }
+}
+
+/** Parent data associated with children. */
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal data class NavigationSuiteParentData(
+ var alignment: NavigationSuiteAlignment? = null
+)
+
+internal val IntrinsicMeasurable.navigationSuiteParentData: NavigationSuiteParentData?
+ get() = parentData as? NavigationSuiteParentData
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal val NavigationSuiteParentData?.alignment: NavigationSuiteAlignment
+ get() = this?.alignment ?: NavigationSuiteAlignment.StartVertical
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal expect val WindowAdaptiveInfoDefault: WindowAdaptiveInfo
+ @Composable
+ get
+
+private interface NavigationSuiteItemProvider {
+ val itemsCount: Int
+ val itemList: MutableVector<NavigationSuiteItem>
+}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+private class NavigationSuiteItem constructor(
+ val selected: Boolean,
+ val onClick: () -> Unit,
+ val icon: @Composable () -> Unit,
+ val modifier: Modifier,
+ val enabled: Boolean,
+ val label: @Composable (() -> Unit)?,
+ val alwaysShowLabel: Boolean,
+ val badge: (@Composable () -> Unit)?,
+ val colors: NavigationSuiteItemColors?,
+ val interactionSource: MutableInteractionSource
+)
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+private class NavigationSuiteScopeImpl : NavigationSuiteScope,
+ NavigationSuiteItemProvider {
+
+ override fun item(
+ selected: Boolean,
+ onClick: () -> Unit,
+ icon: @Composable () -> Unit,
+ modifier: Modifier,
+ enabled: Boolean,
+ label: @Composable (() -> Unit)?,
+ alwaysShowLabel: Boolean,
+ badge: (@Composable () -> Unit)?,
+ colors: NavigationSuiteItemColors?,
+ interactionSource: MutableInteractionSource
+ ) {
+ itemList.add(
+ NavigationSuiteItem(
+ selected = selected,
+ onClick = onClick,
+ icon = icon,
+ modifier = modifier,
+ enabled = enabled,
+ label = label,
+ alwaysShowLabel = alwaysShowLabel,
+ badge = badge,
+ colors = colors,
+ interactionSource = interactionSource
+ )
+ )
+ }
+
+ override val itemList: MutableVector<NavigationSuiteItem> = mutableVectorOf()
+
+ override val itemsCount: Int
+ get() = itemList.size
+}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+@Composable
+private fun rememberStateOfItems(
+ content: NavigationSuiteScope.() -> Unit
+): State<NavigationSuiteItemProvider> {
+ val latestContent = rememberUpdatedState(content)
+ return remember {
+ derivedStateOf { NavigationSuiteScopeImpl().apply(latestContent.value) }
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+private fun NavigationItemIcon(
+ icon: @Composable () -> Unit,
+ badge: (@Composable () -> Unit)? = null,
+) {
+ if (badge != null) {
+ BadgedBox(badge = { badge.invoke() }) {
+ icon()
+ }
+ } else {
+ icon()
+ }
+}
diff --git a/compose/material3/material3-adaptive/src/desktopMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.desktop.kt b/compose/material3/material3-adaptive/src/desktopMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.desktop.kt
new file mode 100644
index 0000000..6a4a617
--- /dev/null
+++ b/compose/material3/material3-adaptive/src/desktopMain/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffold.desktop.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.material3.adaptive
+
+import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
+import androidx.compose.material3.windowsizeclass.WindowSizeClass
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3WindowSizeClassApi::class)
+internal actual val WindowAdaptiveInfoDefault: WindowAdaptiveInfo = WindowAdaptiveInfo(
+ windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(1000.dp, 1000.dp)),
+ posture = Posture()
+)
diff --git a/compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/NavigationSuiteTest.kt b/compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffoldTest.kt
similarity index 71%
rename from compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/NavigationSuiteTest.kt
rename to compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffoldTest.kt
index 91e0f7c..3ab8ee3 100644
--- a/compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/NavigationSuiteTest.kt
+++ b/compose/material3/material3-adaptive/src/test/kotlin/androidx/compose/material3/adaptive/NavigationSuiteScaffoldTest.kt
@@ -27,9 +27,7 @@
@OptIn(ExperimentalMaterial3AdaptiveApi::class, ExperimentalMaterial3WindowSizeClassApi::class)
@RunWith(JUnit4::class)
-class NavigationSuiteTest {
-
- private val layoutTypeProvider = NavigationSuiteDefaults.layoutTypeProvider
+class NavigationSuiteScaffoldTest {
@Test
fun navigationLayoutTypeTest_compactWidth_compactHeight() {
@@ -38,8 +36,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(400.dp, 400.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -49,8 +47,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(400.dp, 800.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -60,8 +58,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(400.dp, 1000.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -71,8 +69,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(800.dp, 400.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -82,8 +80,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(800.dp, 800.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -93,8 +91,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(800.dp, 1000.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -104,8 +102,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(1000.dp, 400.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -115,8 +113,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(1000.dp, 800.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationRail)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationRail)
}
@Test
@@ -126,8 +124,8 @@
windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(1000.dp, 1000.dp))
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationRail)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationRail)
}
@Test
@@ -138,8 +136,8 @@
isTableTop = true
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
@Test
@@ -150,8 +148,8 @@
isTableTop = true
)
- assertThat(layoutTypeProvider.calculateFromAdaptiveInfo(mockAdaptiveInfo))
- .isEqualTo(NavigationLayoutType.NavigationBar)
+ assertThat(NavigationSuiteDefaults.calculateFromAdaptiveInfo(mockAdaptiveInfo))
+ .isEqualTo(NavigationSuiteType.NavigationBar)
}
private fun createMockAdaptiveInfo(
diff --git a/compose/material3/material3/src/androidMain/res/values-am/strings.xml b/compose/material3/material3/src/androidMain/res/values-am/strings.xml
index 31b1eaa1..ac713ec 100644
--- a/compose/material3/material3/src/androidMain/res/values-am/strings.xml
+++ b/compose/material3/material3/src/androidMain/res/values-am/strings.xml
@@ -41,7 +41,7 @@
<string name="m3c_date_input_no_input_description" msgid="1237013946323089826">"ምንም"</string>
<string name="m3c_date_input_invalid_not_allowed" msgid="2521768508935305279">"ቀን አልተፈቀደም፦ %1$s"</string>
<string name="m3c_date_input_invalid_for_pattern" msgid="6116910750161463197">"ቀኑ ከተጠበቀው ስርዓተ ጥለት ጋር አይዛመድም፦ %1$s"</string>
- <string name="m3c_date_input_invalid_year_range" msgid="7052898923934555305">"ቀን ከተጠበቀው የዓመት ክልል ውጪ ነው %1$s - %2$s"</string>
+ <string name="m3c_date_input_invalid_year_range" msgid="7052898923934555305">"ቀን ከተጠበቀው የዓመት ክልል ውጭ ነው %1$s - %2$s"</string>
<string name="m3c_date_picker_switch_to_calendar_mode" msgid="1804346892470238807">"ወደ የቀን መቁጠሪያ ግቤት ሁነታ ይቀይሩ"</string>
<string name="m3c_date_picker_switch_to_input_mode" msgid="2219746470065162704">"ወደ የጽሁፍ ግቤት ሁነታ ይቀይሩ"</string>
<string name="m3c_date_picker_scroll_to_later_years" msgid="5727367015496556177">"ከዚህ በኋላ ያሉ ዓመታትን ለማሳየት ያሸብልሉ"</string>
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index 31650af..fc64f3a 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -2006,18 +2006,14 @@
if (inserting) {
providers = parentScope.putValue(local, state)
invalid = false
+ writerHasAProvider = true
} else {
val oldScope = reader.groupAux(reader.currentGroup) as PersistentCompositionLocalMap
providers =
if ((!skipping || change) && (value.canOverride || !parentScope.contains(local)))
parentScope.putValue(local, state)
else oldScope
- if (oldScope !== providers) {
- invalid = true
- writerHasAProvider = true
- } else {
- invalid = false
- }
+ invalid = reusing || oldScope !== providers
}
if (invalid && !inserting) {
providerUpdates[reader.currentGroup] = providers
@@ -3333,6 +3329,7 @@
private fun reportFreeMovableContent(groupBeingRemoved: Int) {
fun reportGroup(group: Int, needsNodeDelete: Boolean, nodeIndex: Int): Int {
+ val reader = reader
return if (reader.hasMark(group)) {
// If the group has a mark then it is either a movable content group or a
// composition context group
@@ -3390,7 +3387,7 @@
}
}
reader.nodeCount(group)
- } else reader.nodeCount(group)
+ } else if (reader.isNode(group)) 1 else reader.nodeCount(group)
} else if (reader.containsMark(group)) {
// Traverse the group freeing the child movable content. This group is known to
// have at least one child that contains movable content because the group is
@@ -3423,8 +3420,8 @@
}
current += reader.groupSize(current)
}
- runningNodeCount
- } else reader.nodeCount(group)
+ if (reader.isNode(group)) 1 else runningNodeCount
+ } else if (reader.isNode(group)) 1 else reader.nodeCount(group)
}
reportGroup(groupBeingRemoved, needsNodeDelete = false, nodeIndex = 0)
changeListWriter.endNodeMovement()
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
index cde9d7c..1073e39 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionLocal.kt
@@ -244,10 +244,9 @@
@Composable
@OptIn(InternalComposeApi::class)
fun CompositionLocalProvider(value: ProvidedValue<*>, content: @Composable () -> Unit) {
- // TODO(b/292224893): Switch this to the higher-performance startProvider()
- currentComposer.startProviders(arrayOf(value))
+ currentComposer.startProvider(value)
content()
- currentComposer.endProviders()
+ currentComposer.endProvider()
}
/**
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
index 1289e49..4144ccd 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/CompositionLocalTests.kt
@@ -568,6 +568,44 @@
}
}
+ @Suppress("UNUSED_EXPRESSION")
+ @Test // Regression for b/292224893
+ fun testSingleInvalidatedProvider() = compositionTest {
+ val local1 = compositionLocalOf { 10 }
+ val local2 = compositionLocalOf { 20 }
+ val local3 = compositionLocalOf { 30 }
+ var state by mutableStateOf(0)
+
+ compose {
+ state
+ CompositionLocalProvider(local1 provides 11) {
+ state
+ CompositionLocalProvider(local2 provides 22) {
+ state
+ CompositionLocalProvider(local3 provides 33) {
+ state
+ assertEquals(11, local1.current)
+ assertEquals(22, local2.current)
+ assertEquals(33, local3.current)
+ }
+ assertEquals(11, local1.current)
+ assertEquals(22, local2.current)
+ assertEquals(30, local3.current)
+ }
+ assertEquals(11, local1.current)
+ assertEquals(20, local2.current)
+ assertEquals(30, local3.current)
+ }
+ assertEquals(10, local1.current)
+ assertEquals(20, local2.current)
+ assertEquals(30, local3.current)
+ }
+
+ state++
+
+ advance()
+ }
+
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testProvideAllLocals() = compositionTest {
diff --git a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
index d3d1a87..dcda328 100644
--- a/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
+++ b/compose/runtime/runtime/src/nonEmulatorCommonTest/kotlin/androidx/compose/runtime/MovableContentTests.kt
@@ -16,6 +16,7 @@
package androidx.compose.runtime
+import androidx.compose.runtime.mock.Linear
import androidx.compose.runtime.mock.MockViewValidator
import androidx.compose.runtime.mock.View
import androidx.compose.runtime.mock.ViewApplier
@@ -1541,6 +1542,50 @@
assertEquals(state, lastSeen)
}
+
+ @Test
+ fun movableContent_moveRow() = compositionTest {
+ var condition by mutableStateOf(true)
+
+ val movableContent1 = movableContentOf {
+ Text("First")
+ }
+ val movableContent2 = movableContentOf {
+ Text("Second")
+ }
+
+ compose {
+ if (condition) {
+ Linear {
+ Linear {
+ movableContent1()
+ }
+ movableContent2()
+ }
+ } else {
+ Linear {
+ Linear {
+ movableContent1()
+ }
+ movableContent2()
+ }
+ }
+ }
+
+ validate {
+ Linear {
+ Linear {
+ Text("First")
+ }
+ Text("Second")
+ }
+ }
+
+ condition = false
+ expectChanges()
+
+ revalidate()
+ }
}
@Composable
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt
index 49bc878..d34d4bc 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/TestOwner.kt
@@ -93,8 +93,10 @@
}
}
- return roots.flatMap {
- it.semanticsOwner.getAllSemanticsNodes(mergingEnabled = !useUnmergedTree)
+ return testOwner.runOnUiThread {
+ roots.flatMap {
+ it.semanticsOwner.getAllSemanticsNodes(mergingEnabled = !useUnmergedTree)
+ }
}
}
}
diff --git a/compose/ui/ui-text/api/current.ignore b/compose/ui/ui-text/api/current.ignore
index fe35567..b615cf0 100644
--- a/compose/ui/ui-text/api/current.ignore
+++ b/compose/ui/ui-text/api/current.ignore
@@ -9,3 +9,9 @@
Attempted to change parameter name from fallbackDensity to defaultDensity in constructor androidx.compose.ui.text.TextMeasurer
ParameterNameChange: androidx.compose.ui.text.TextMeasurer#TextMeasurer(androidx.compose.ui.text.font.FontFamily.Resolver, androidx.compose.ui.unit.Density, androidx.compose.ui.unit.LayoutDirection, int) parameter #2:
Attempted to change parameter name from fallbackLayoutDirection to defaultLayoutDirection in constructor androidx.compose.ui.text.TextMeasurer
+
+
+RemovedMethod: androidx.compose.ui.text.input.ImeOptions#ImeOptions(boolean, int, boolean, int, int):
+ Removed constructor androidx.compose.ui.text.input.ImeOptions(boolean,int,boolean,int,int)
+RemovedMethod: androidx.compose.ui.text.input.ImeOptions#copy(boolean, int, boolean, int, int):
+ Removed method androidx.compose.ui.text.input.ImeOptions.copy(boolean,int,boolean,int,int)
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index 01fa582..f6bb7575a 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -911,6 +911,12 @@
package androidx.compose.ui.text.input {
+ public final class AndroidImeOptions implements androidx.compose.ui.text.input.PlatformImeOptions {
+ ctor public AndroidImeOptions(optional String? privateImeOptions);
+ method public String? getPrivateImeOptions();
+ property public final String? privateImeOptions;
+ }
+
public final class BackspaceCommand implements androidx.compose.ui.text.input.EditCommand {
ctor public BackspaceCommand();
method public void applyTo(androidx.compose.ui.text.input.EditingBuffer buffer);
@@ -995,17 +1001,21 @@
}
@androidx.compose.runtime.Immutable public final class ImeOptions {
- ctor public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
- method public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor @Deprecated public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+ method @Deprecated public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ method public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
method public boolean getAutoCorrect();
method public int getCapitalization();
method public int getImeAction();
method public int getKeyboardType();
+ method public androidx.compose.ui.text.input.PlatformImeOptions? getPlatformImeOptions();
method public boolean getSingleLine();
property public final boolean autoCorrect;
property public final int capitalization;
property public final int imeAction;
property public final int keyboardType;
+ property public final androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions;
property public final boolean singleLine;
field public static final androidx.compose.ui.text.input.ImeOptions.Companion Companion;
}
@@ -1085,6 +1095,9 @@
property public final char mask;
}
+ public sealed interface PlatformImeOptions {
+ }
+
public fun interface PlatformTextInputMethodRequest {
method public android.view.inputmethod.InputConnection createInputConnection(android.view.inputmethod.EditorInfo outAttrs);
}
diff --git a/compose/ui/ui-text/api/restricted_current.ignore b/compose/ui/ui-text/api/restricted_current.ignore
index fe35567..b615cf0 100644
--- a/compose/ui/ui-text/api/restricted_current.ignore
+++ b/compose/ui/ui-text/api/restricted_current.ignore
@@ -9,3 +9,9 @@
Attempted to change parameter name from fallbackDensity to defaultDensity in constructor androidx.compose.ui.text.TextMeasurer
ParameterNameChange: androidx.compose.ui.text.TextMeasurer#TextMeasurer(androidx.compose.ui.text.font.FontFamily.Resolver, androidx.compose.ui.unit.Density, androidx.compose.ui.unit.LayoutDirection, int) parameter #2:
Attempted to change parameter name from fallbackLayoutDirection to defaultLayoutDirection in constructor androidx.compose.ui.text.TextMeasurer
+
+
+RemovedMethod: androidx.compose.ui.text.input.ImeOptions#ImeOptions(boolean, int, boolean, int, int):
+ Removed constructor androidx.compose.ui.text.input.ImeOptions(boolean,int,boolean,int,int)
+RemovedMethod: androidx.compose.ui.text.input.ImeOptions#copy(boolean, int, boolean, int, int):
+ Removed method androidx.compose.ui.text.input.ImeOptions.copy(boolean,int,boolean,int,int)
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index 01fa582..f6bb7575a 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -911,6 +911,12 @@
package androidx.compose.ui.text.input {
+ public final class AndroidImeOptions implements androidx.compose.ui.text.input.PlatformImeOptions {
+ ctor public AndroidImeOptions(optional String? privateImeOptions);
+ method public String? getPrivateImeOptions();
+ property public final String? privateImeOptions;
+ }
+
public final class BackspaceCommand implements androidx.compose.ui.text.input.EditCommand {
ctor public BackspaceCommand();
method public void applyTo(androidx.compose.ui.text.input.EditingBuffer buffer);
@@ -995,17 +1001,21 @@
}
@androidx.compose.runtime.Immutable public final class ImeOptions {
- ctor public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
- method public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor @Deprecated public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ ctor public ImeOptions(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
+ method @Deprecated public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction);
+ method public androidx.compose.ui.text.input.ImeOptions copy(optional boolean singleLine, optional int capitalization, optional boolean autoCorrect, optional int keyboardType, optional int imeAction, optional androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions);
method public boolean getAutoCorrect();
method public int getCapitalization();
method public int getImeAction();
method public int getKeyboardType();
+ method public androidx.compose.ui.text.input.PlatformImeOptions? getPlatformImeOptions();
method public boolean getSingleLine();
property public final boolean autoCorrect;
property public final int capitalization;
property public final int imeAction;
property public final int keyboardType;
+ property public final androidx.compose.ui.text.input.PlatformImeOptions? platformImeOptions;
property public final boolean singleLine;
field public static final androidx.compose.ui.text.input.ImeOptions.Companion Companion;
}
@@ -1085,6 +1095,9 @@
property public final char mask;
}
+ public sealed interface PlatformImeOptions {
+ }
+
public fun interface PlatformTextInputMethodRequest {
method public android.view.inputmethod.InputConnection createInputConnection(android.view.inputmethod.EditorInfo outAttrs);
}
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.android.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.android.kt
new file mode 100644
index 0000000..e274e69
--- /dev/null
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.android.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.ui.text.input
+
+/**
+ * Used to configure the platform specific IME options.
+ */
+actual sealed interface PlatformImeOptions
+
+/**
+ * Used to configure Android platform IME options.
+ *
+ * @param privateImeOptions defines a [String] for supplying additional information options that
+ * are private to a particular IME implementation.
+ */
+class AndroidImeOptions(val privateImeOptions: String? = null) : PlatformImeOptions {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other !is AndroidImeOptions) return false
+
+ if (privateImeOptions != other.privateImeOptions) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ return privateImeOptions?.hashCode() ?: 0
+ }
+
+ override fun toString(): String {
+ return "AndroidImeOptions(privateImeOptions=$privateImeOptions)"
+ }
+}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt
index abc8377..8a45b44 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/ImeOptions.kt
@@ -38,6 +38,7 @@
* @param imeAction The IME action. This IME action is honored by IME and may show specific icons
* on the keyboard. For example, search icon may be shown if [ImeAction.Search] is specified.
* When [singleLine] is false, the IME might show return key rather than the action requested here.
+ * @param platformImeOptions defines the platform specific IME options.
*/
@Immutable
class ImeOptions(
@@ -45,7 +46,8 @@
val capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
val autoCorrect: Boolean = true,
val keyboardType: KeyboardType = KeyboardType.Text,
- val imeAction: ImeAction = ImeAction.Default
+ val imeAction: ImeAction = ImeAction.Default,
+ val platformImeOptions: PlatformImeOptions? = null
) {
companion object {
/**
@@ -54,6 +56,47 @@
val Default = ImeOptions()
}
+ @Deprecated(
+ "Please use the new constructor that takes optional platformImeOptions parameter.",
+ level = DeprecationLevel.HIDDEN
+ )
+ constructor(
+ singleLine: Boolean = false,
+ capitalization: KeyboardCapitalization = KeyboardCapitalization.None,
+ autoCorrect: Boolean = true,
+ keyboardType: KeyboardType = KeyboardType.Text,
+ imeAction: ImeAction = ImeAction.Default,
+ ) : this(
+ singleLine = singleLine,
+ capitalization = capitalization,
+ autoCorrect = autoCorrect,
+ keyboardType = keyboardType,
+ imeAction = imeAction,
+ platformImeOptions = null
+ )
+
+ fun copy(
+ singleLine: Boolean = this.singleLine,
+ capitalization: KeyboardCapitalization = this.capitalization,
+ autoCorrect: Boolean = this.autoCorrect,
+ keyboardType: KeyboardType = this.keyboardType,
+ imeAction: ImeAction = this.imeAction,
+ platformImeOptions: PlatformImeOptions? = this.platformImeOptions
+ ): ImeOptions {
+ return ImeOptions(
+ singleLine = singleLine,
+ capitalization = capitalization,
+ autoCorrect = autoCorrect,
+ keyboardType = keyboardType,
+ imeAction = imeAction,
+ platformImeOptions = platformImeOptions
+ )
+ }
+
+ @Deprecated(
+ "Please use the new copy function that takes optional platformImeOptions parameter.",
+ level = DeprecationLevel.HIDDEN
+ )
fun copy(
singleLine: Boolean = this.singleLine,
capitalization: KeyboardCapitalization = this.capitalization,
@@ -66,7 +109,8 @@
capitalization = capitalization,
autoCorrect = autoCorrect,
keyboardType = keyboardType,
- imeAction = imeAction
+ imeAction = imeAction,
+ platformImeOptions = this.platformImeOptions
)
}
@@ -79,6 +123,7 @@
if (autoCorrect != other.autoCorrect) return false
if (keyboardType != other.keyboardType) return false
if (imeAction != other.imeAction) return false
+ if (platformImeOptions != other.platformImeOptions) return false
return true
}
@@ -89,11 +134,13 @@
result = 31 * result + autoCorrect.hashCode()
result = 31 * result + keyboardType.hashCode()
result = 31 * result + imeAction.hashCode()
+ result = 31 * result + platformImeOptions.hashCode()
return result
}
override fun toString(): String {
return "ImeOptions(singleLine=$singleLine, capitalization=$capitalization, " +
- "autoCorrect=$autoCorrect, keyboardType=$keyboardType, imeAction=$imeAction)"
+ "autoCorrect=$autoCorrect, keyboardType=$keyboardType, imeAction=$imeAction, " +
+ "platformImeOptions=$platformImeOptions)"
}
}
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.kt
similarity index 63%
copy from core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
copy to compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.kt
index 9914490..a9ade23 100644
--- a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.kt
@@ -14,17 +14,9 @@
* limitations under the License.
*/
-package androidx.core.performance
+package androidx.compose.ui.text.input
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [DevicePerformance]. */
-class DevicePerformanceTest {
-
- @Test
- fun mediaPerformanceClass() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
+/**
+ * Used to configure the platform specific IME options.
+ */
+expect sealed interface PlatformImeOptions
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.desktop.kt
similarity index 62%
copy from core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
copy to compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.desktop.kt
index 9914490..60607ca 100644
--- a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
+++ b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/input/PlatformImeOptions.desktop.kt
@@ -14,17 +14,9 @@
* limitations under the License.
*/
-package androidx.core.performance
+package androidx.compose.ui.text.input
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [DevicePerformance]. */
-class DevicePerformanceTest {
-
- @Test
- fun mediaPerformanceClass() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
+/**
+ * Used to configure the platform specific IME options.
+ */
+actual sealed interface PlatformImeOptions
diff --git a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
index 48b3e9c..5377348 100644
--- a/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
+++ b/compose/ui/ui-tooling/src/androidAndroidTest/kotlin/androidx/compose/ui/tooling/animation/clock/TransitionClockTest.kt
@@ -599,7 +599,8 @@
clock.setStateParameters(10.dp, 10.dp)
}
rule.runOnIdle {
- assertEquals(2, clock.getAnimatedProperties().size)
+ // When initial == target state, no animation is active.
+ assertEquals(0, clock.getAnimatedProperties().size)
clock.setStateParameters(20.dp, 40.dp)
}
rule.runOnIdle {
@@ -619,19 +620,8 @@
rule.runOnIdle {
// Default clock state.
clock.getTransitions(100).let {
- assertEquals(2, it.size)
- it[0].let { info ->
- assertEquals(0, info.startTimeMillis)
- assertEquals(0, info.endTimeMillis)
- assertEquals(1, info.values.size)
- assertNotNull(info.specType)
- }
- it[1].let { info ->
- assertEquals(0, info.startTimeMillis)
- assertEquals(0, info.endTimeMillis)
- assertEquals(1, info.values.size)
- assertNotNull(info.specType)
- }
+ // When initial == target state, no animation is active.
+ assertEquals(0, it.size)
}
// Change state
clock.setStateParameters(20.dp, 40.dp)
diff --git a/compose/ui/ui-util/src/androidMain/kotlin/androidx/compose/ui/util/AndroidTrace.android.kt b/compose/ui/ui-util/src/androidMain/kotlin/androidx/compose/ui/util/AndroidTrace.android.kt
index 266bbf5..da5318c 100644
--- a/compose/ui/ui-util/src/androidMain/kotlin/androidx/compose/ui/util/AndroidTrace.android.kt
+++ b/compose/ui/ui-util/src/androidMain/kotlin/androidx/compose/ui/util/AndroidTrace.android.kt
@@ -22,7 +22,7 @@
* Wrap the specified [block] in calls to [Trace.beginSection] (with the supplied [sectionName])
* and [Trace.endSection].
*/
-inline fun <T> trace(sectionName: String, block: () -> T): T {
+actual inline fun <T> trace(sectionName: String, block: () -> T): T {
Trace.beginSection(sectionName)
try {
return block()
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt b/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/Trace.kt
similarity index 63%
copy from core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
copy to compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/Trace.kt
index 9914490..d940938 100644
--- a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
+++ b/compose/ui/ui-util/src/commonMain/kotlin/androidx/compose/ui/util/Trace.kt
@@ -14,17 +14,6 @@
* limitations under the License.
*/
-package androidx.core.performance
+package androidx.compose.ui.util
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [DevicePerformance]. */
-class DevicePerformanceTest {
-
- @Test
- fun mediaPerformanceClass() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
+expect inline fun <T> trace(sectionName: String, block: () -> T): T
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt b/compose/ui/ui-util/src/desktopMain/kotlin/androidx/compose/ui/util/Trace.desktop.kt
similarity index 63%
rename from core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
rename to compose/ui/ui-util/src/desktopMain/kotlin/androidx/compose/ui/util/Trace.desktop.kt
index 9914490..f006190 100644
--- a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
+++ b/compose/ui/ui-util/src/desktopMain/kotlin/androidx/compose/ui/util/Trace.desktop.kt
@@ -14,17 +14,6 @@
* limitations under the License.
*/
-package androidx.core.performance
+package androidx.compose.ui.util
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [DevicePerformance]. */
-class DevicePerformanceTest {
-
- @Test
- fun mediaPerformanceClass() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
+actual inline fun <T> trace(sectionName: String, block: () -> T): T = block()
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 5ac963d..07a53a6 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2175,14 +2175,14 @@
@Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public sealed interface LookaheadLayoutCoordinates extends androidx.compose.ui.layout.LayoutCoordinates {
}
- @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public interface LookaheadScope {
+ public interface LookaheadScope {
method public androidx.compose.ui.layout.LayoutCoordinates getLookaheadScopeCoordinates(androidx.compose.ui.layout.Placeable.PlacementScope);
- method public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
- method public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
+ method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
+ method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
}
public final class LookaheadScopeKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.compose.ui.ExperimentalComposeUiApi @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier intermediateLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.IntermediateMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measure);
}
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index f3078e1..ec0b3c9 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2178,14 +2178,14 @@
@Deprecated @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public sealed interface LookaheadLayoutCoordinates extends androidx.compose.ui.layout.LayoutCoordinates {
}
- @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public interface LookaheadScope {
+ public interface LookaheadScope {
method public androidx.compose.ui.layout.LayoutCoordinates getLookaheadScopeCoordinates(androidx.compose.ui.layout.Placeable.PlacementScope);
- method public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
- method public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
+ method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public default long localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates, androidx.compose.ui.layout.LayoutCoordinates coordinates);
+ method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public androidx.compose.ui.layout.LayoutCoordinates toLookaheadCoordinates(androidx.compose.ui.layout.LayoutCoordinates);
}
public final class LookaheadScopeKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.compose.ui.ExperimentalComposeUiApi @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
+ method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static void LookaheadScope(kotlin.jvm.functions.Function1<? super androidx.compose.ui.layout.LookaheadScope,kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.ui.ExperimentalComposeUiApi public static androidx.compose.ui.Modifier intermediateLayout(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function3<? super androidx.compose.ui.layout.IntermediateMeasureScope,? super androidx.compose.ui.layout.Measurable,? super androidx.compose.ui.unit.Constraints,? extends androidx.compose.ui.layout.MeasureResult> measure);
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
index 93604d6..e905ca7 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidLayoutDrawTest.kt
@@ -1953,11 +1953,12 @@
// This simulates a child that recomposes, for example due to a transition.
content(offset.value)
}
- val assumeLayoutBeforeDraw = @Composable { _: Int ->
+ val assumeLayoutBeforeDraw = @Composable { value: Int ->
// This assumes a layout was done before the draw pass.
Layout(
content = {},
modifier = Modifier.drawBehind {
+ assertEquals(offset.value, value)
assertTrue(laidOut)
latch.countDown()
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt
index f99c430..0bcfbd9c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/vector/VectorTest.kt
@@ -34,6 +34,7 @@
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.testutils.assertPixels
@@ -164,6 +165,50 @@
}
}
+ @Test
+ fun testVectorSkipsRecompositionOnNoChange() {
+ val state = mutableIntStateOf(0)
+ var composeCount = 0
+ var vectorComposeCount = 0
+
+ val composeVector: @Composable @VectorComposable (Float, Float) -> Unit = {
+ viewportWidth, viewportHeight ->
+
+ vectorComposeCount++
+ Path(
+ fill = SolidColor(Color.Blue),
+ pathData = PathData {
+ lineTo(viewportWidth, 0f)
+ lineTo(viewportWidth, viewportHeight)
+ lineTo(0f, viewportHeight)
+ close()
+ }
+ )
+ }
+
+ rule.setContent {
+ composeCount++
+ // Arbitrary read to force composition here and verify the subcomposition below skips
+ state.value
+ val vectorPainter = rememberVectorPainter(
+ defaultWidth = 10.dp,
+ defaultHeight = 10.dp,
+ autoMirror = false,
+ content = composeVector
+ )
+ Image(
+ vectorPainter,
+ null,
+ modifier = Modifier.size(20.dp)
+ )
+ }
+
+ state.value = 1
+ rule.waitForIdle()
+ assertEquals(2, composeCount) // Arbitrary state read should compose twice
+ assertEquals(1, vectorComposeCount) // Vector is identical so should compose once
+ }
+
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun testVectorInvalidation() {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
index caf9dbb..ddd1083 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/EditorInfoTest.kt
@@ -19,6 +19,7 @@
import android.text.InputType
import android.view.inputmethod.EditorInfo
import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.AndroidImeOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.ImeOptions
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -537,6 +538,19 @@
assertThat(info.initialSelEnd).isEqualTo(selection.end)
}
+ @Test
+ fun test_privateImeOptions_is_set() {
+ val info = EditorInfo()
+ val privateImeOptions = "testOptions"
+ info.update(
+ ImeOptions(
+ platformImeOptions = AndroidImeOptions(privateImeOptions)
+ )
+ )
+
+ assertThat(info.privateImeOptions).isEqualTo(privateImeOptions)
+ }
+
private fun EditorInfo.update(imeOptions: ImeOptions) {
this.update(imeOptions, TextFieldValue())
}
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
index 7f3e41e..1725987 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/LookaheadScopeTest.kt
@@ -19,6 +19,7 @@
package androidx.compose.ui.layout
import androidx.activity.ComponentActivity
+import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.VectorConverter
@@ -28,6 +29,9 @@
import androidx.compose.foundation.layout.Arrangement.Absolute.SpaceAround
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowColumn
+import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -36,6 +40,7 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
@@ -46,6 +51,7 @@
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -91,6 +97,7 @@
import junit.framework.TestCase.assertTrue
import kotlin.math.roundToInt
import kotlin.random.Random
+import kotlin.test.assertNotNull
import kotlinx.coroutines.launch
import org.junit.Ignore
import org.junit.Rule
@@ -1264,6 +1271,83 @@
}
}
+ @OptIn(ExperimentalLayoutApi::class)
+ @Test
+ fun testNestedLookaheadPlacement() {
+ var expanded by mutableStateOf(true)
+ var actualOffset: Offset? = null
+ var lookaheadOffset: Offset? = null
+ rule.setContent {
+ LookaheadScope {
+ FlowRow(
+ modifier = Modifier.fillMaxSize(),
+ horizontalArrangement = Arrangement.Center,
+ verticalArrangement = Arrangement.Center,
+ maxItemsInEachRow = 3
+ ) {
+ Box(
+ modifier = Modifier
+ .animateContentSize()
+ .widthIn(max = 600.dp)
+ .background(Color.Red)
+ ) {
+ val height = if (expanded) 500.dp else 300.dp
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(height)
+ )
+ }
+
+ FlowColumn {
+ Box(
+ modifier = Modifier
+ .size(200.dp)
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ val coords = coordinates
+ if (coords != null) {
+ if (isLookingAhead) {
+ lookaheadOffset = coords
+ .findRootCoordinates()
+ .localLookaheadPositionOf(coords)
+ } else {
+ actualOffset = coords
+ .findRootCoordinates()
+ .localPositionOf(coords, Offset.Zero)
+ }
+ }
+ placeable.place(0, 0)
+ }
+ }
+ .wrapContentWidth()
+ .heightIn(min = 156.dp)
+ .background(Color.Blue)
+ ) {
+ Box(modifier = Modifier.size(200.dp))
+ }
+ }
+ }
+ }
+ }
+ rule.runOnIdle {
+ expanded = !expanded
+ }
+ rule.runOnIdle {
+ assertNotNull(actualOffset)
+ assertEquals(actualOffset, lookaheadOffset)
+ actualOffset = null
+ lookaheadOffset = null
+
+ expanded = !expanded
+ }
+ rule.runOnIdle {
+ assertNotNull(actualOffset)
+ assertEquals(actualOffset, lookaheadOffset)
+ }
+ }
+
@Test
fun grandparentQueryBaseline() {
assertSameLayoutWithAndWithoutLookahead { modifier ->
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacedChildTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacedChildTest.kt
index 27d5a6b..cb754c6 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacedChildTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/PlacedChildTest.kt
@@ -16,11 +16,36 @@
package androidx.compose.ui.layout
+import android.os.Build
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.testutils.assertPixels
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.background
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.node.LayoutNode
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.TestActivity
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createAndroidComposeRule
+import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -28,6 +53,11 @@
@RunWith(AndroidJUnit4::class)
class PlacedChildTest {
+ private val Tag = "tag"
+
+ @get:Rule
+ val rule = createAndroidComposeRule<TestActivity>()
+
@Test
fun remeasureNotPlacedChild() {
val root = root {
@@ -55,6 +85,131 @@
assertThat(root.height).isEqualTo(20)
}
+
+ @Test
+ fun addingAndRemovingNotPlacingModifier() {
+ var visible by mutableStateOf(false)
+ rule.setContent {
+ Box(
+ Modifier
+ .then(
+ if (visible) Modifier else Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ }
+ }
+ )
+ .size(10.dp)
+ .testTag(Tag)
+ )
+ }
+
+ rule.runOnIdle {
+ visible = true
+ }
+
+ rule.onNodeWithTag(Tag)
+ .assertIsDisplayed()
+
+ rule.runOnIdle {
+ visible = false
+ }
+
+ rule.onNodeWithTag(Tag)
+ .assertIsNotDisplayed()
+ }
+
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun drawingOrderIsCorrectWhenAddingAndRemovingNotPlacingModifier() {
+ var visible by mutableStateOf(false)
+ val size = 4
+ val halfSize = 4 / 2
+ val sizeDp = with(rule.density) { size.toDp() }
+ val halfSizeDp = with(rule.density) { halfSize.toDp() }
+ rule.setContent {
+ Box(Modifier.background(Color.Black).size(sizeDp).testTag(Tag)) {
+ Box(
+ Modifier
+ .then(
+ if (visible) Modifier else Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ }
+ }
+ )
+ .fillMaxSize()
+ .background(Color.Red)
+ )
+ Box(
+ Modifier
+ .offset(y = halfSizeDp)
+ .height(halfSizeDp)
+ .fillMaxWidth()
+ .background(Color.Green)
+ )
+ }
+ }
+
+ rule.runOnIdle {
+ visible = true
+ }
+
+ rule.onNodeWithTag(Tag)
+ .captureToImage()
+ .assertPixels(expectedSize = IntSize(size, size)) { offset ->
+ if (offset.y < halfSize) {
+ Color.Red
+ } else {
+ Color.Green
+ }
+ }
+
+ rule.runOnIdle {
+ visible = false
+ }
+
+ rule.onNodeWithTag(Tag)
+ .captureToImage()
+ .assertPixels(expectedSize = IntSize(size, size)) { offset ->
+ if (offset.y < halfSize) {
+ Color.Black
+ } else {
+ Color.Green
+ }
+ }
+ }
+
+ @Test
+ fun notPlacedChildIsNotCallingPlacingBlockOnItsModifier() {
+ var modifier by mutableStateOf<Modifier>(Modifier)
+ rule.setContent {
+ Layout(content = {
+ Box(modifier.size(10.dp))
+ }) { measurables, constraints ->
+ val placeable = measurables.first().measure(constraints)
+ layout(placeable.width, placeable.height) { }
+ }
+ }
+
+ var measureCount = 0
+ var placementCount = 0
+ rule.runOnIdle {
+ modifier = Modifier.layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ measureCount++
+ layout(placeable.width, placeable.height) {
+ placementCount++
+ placeable.place(0, 0)
+ }
+ }
+ }
+
+ rule.runOnIdle {
+ assertThat(measureCount).isEqualTo(1)
+ assertThat(placementCount).isEqualTo(0)
+ }
+ }
}
private val UseChildSizeButNotPlace = object : LayoutNode.NoIntrinsicsMeasurePolicy("") {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
index be9b6c5..a37b4e5 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/text/input/TextInputServiceAndroid.android.kt
@@ -500,6 +500,9 @@
ImeAction.Done -> EditorInfo.IME_ACTION_DONE
else -> error("invalid ImeAction")
}
+ (imeOptions.platformImeOptions as? AndroidImeOptions)?.privateImeOptions?.let {
+ privateImeOptions = it
+ }
when (imeOptions.keyboardType) {
KeyboardType.Text -> this.inputType = InputType.TYPE_CLASS_TEXT
KeyboardType.Ascii -> {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/Vector.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/Vector.kt
index 2eed50f..4690c99 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/Vector.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/Vector.kt
@@ -19,6 +19,8 @@
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.Size.Companion.Unspecified
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
@@ -32,6 +34,7 @@
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.graphics.drawscope.withTransform
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
@@ -88,18 +91,12 @@
internal class VectorComponent : VNode() {
val root = GroupComponent().apply {
- pivotX = 0.0f
- pivotY = 0.0f
invalidateListener = {
doInvalidate()
}
}
- var name: String
- get() = root.name
- set(value) {
- root.name = value
- }
+ var name: String = DefaultGroupName
private fun doInvalidate() {
isDirty = true
@@ -114,29 +111,22 @@
internal var intrinsicColorFilter: ColorFilter? by mutableStateOf(null)
- var viewportWidth = 0f
- set(value) {
- if (field != value) {
- field = value
- doInvalidate()
- }
- }
-
- var viewportHeight = 0f
- set(value) {
- if (field != value) {
- field = value
- doInvalidate()
- }
- }
+ internal var viewportSize by mutableStateOf(Size.Zero)
private var previousDrawSize = Unspecified
+ private var rootScaleX = 1f
+ private var rootScaleY = 1f
+
/**
* Cached lambda used to avoid allocating the lambda on each draw invocation
*/
private val drawVectorBlock: DrawScope.() -> Unit = {
- with(root) { draw() }
+ with(root) {
+ scale(rootScaleX, rootScaleY, pivot = Offset.Zero) {
+ draw()
+ }
+ }
}
fun DrawScope.draw(alpha: Float, colorFilter: ColorFilter?) {
@@ -144,8 +134,8 @@
// If the content of the vector has changed, or we are drawing a different size
// update the cached image to ensure we are scaling the vector appropriately
if (isDirty || previousDrawSize != size) {
- root.scaleX = size.width / viewportWidth
- root.scaleY = size.height / viewportHeight
+ rootScaleX = size.width / viewportSize.width
+ rootScaleY = size.height / viewportSize.height
cacheDrawScope.drawCachedImage(
IntSize(ceil(size.width).toInt(), ceil(size.height).toInt()),
this@draw,
@@ -166,8 +156,8 @@
return buildString {
append("Params: ")
append("\tname: ").append(name).append("\n")
- append("\tviewportWidth: ").append(viewportWidth).append("\n")
- append("\tviewportHeight: ").append(viewportHeight).append("\n")
+ append("\tviewportWidth: ").append(viewportSize.width).append("\n")
+ append("\tviewportHeight: ").append(viewportSize.height).append("\n")
}
}
}
@@ -247,29 +237,23 @@
var trimPathStart = DefaultTrimPathStart
set(value) {
- if (field != value) {
- field = value
- isTrimPathDirty = true
- invalidate()
- }
+ field = value
+ isTrimPathDirty = true
+ invalidate()
}
var trimPathEnd = DefaultTrimPathEnd
set(value) {
- if (field != value) {
- field = value
- isTrimPathDirty = true
- invalidate()
- }
+ field = value
+ isTrimPathDirty = true
+ invalidate()
}
var trimPathOffset = DefaultTrimPathOffset
set(value) {
- if (field != value) {
- field = value
- isTrimPathDirty = true
- invalidate()
- }
+ field = value
+ isTrimPathDirty = true
+ invalidate()
}
private var isPathDirty = true
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt
index 648babc7..aafdf94 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt
@@ -19,8 +19,6 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposableOpenTarget
import androidx.compose.runtime.Composition
-import androidx.compose.runtime.CompositionContext
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
@@ -145,7 +143,25 @@
size = Size(widthPx, heightPx)
this.autoMirror = autoMirror
this.intrinsicColorFilter = intrinsicColorFilter
- RenderVector(name, vpWidth, vpHeight, content)
+ this.viewportSize = Size(vpWidth, vpHeight)
+ this.name = name
+
+ val compositionContext = rememberCompositionContext()
+ this.composition = remember(viewportWidth, viewportHeight, content) {
+ val curComp = this.composition
+ val next = if (curComp == null || curComp.isDisposed) {
+ Composition(
+ VectorApplier(this.vector.root),
+ compositionContext
+ )
+ } else {
+ curComp
+ }
+ next.setContent {
+ content(vpWidth, vpHeight)
+ }
+ next
+ }
}
}
@@ -170,6 +186,15 @@
)
/**
+ * Functional interface to avoid "PrimitiveInLambda" lint errors
+ */
+internal fun interface ComposeVector {
+
+ @Composable
+ fun Content(viewportWidth: Float, viewportHeight: Float)
+}
+
+/**
* [Painter] implementation that abstracts the drawing of a Vector graphic.
* This can be represented by either a [ImageVector] or a programmatic
* composition of a vector
@@ -189,7 +214,19 @@
vector.intrinsicColorFilter = value
}
- private val vector = VectorComponent().apply {
+ internal var viewportSize: Size
+ get() = vector.viewportSize
+ set(value) {
+ vector.viewportSize = value
+ }
+
+ internal var name: String
+ get() = vector.name
+ set(value) {
+ vector.name = value
+ }
+
+ internal val vector = VectorComponent().apply {
invalidateCallback = {
if (drawCount == invalidateCount) {
invalidateCount++
@@ -197,55 +234,11 @@
}
}
- private var composition: Composition? = null
-
- private fun composeVector(
- parent: CompositionContext,
- composable: @Composable (viewportWidth: Float, viewportHeight: Float) -> Unit
- ): Composition {
- val existing = composition
- val next = if (existing == null || existing.isDisposed) {
- Composition(
- VectorApplier(vector.root),
- parent
- )
- } else {
- existing
- }
- composition = next
- next.setContent {
- composable(vector.viewportWidth, vector.viewportHeight)
- }
- return next
- }
+ internal var composition: Composition? = null
// TODO replace with mutableStateOf(Unit, neverEqualPolicy()) after b/291647821 is addressed
private var invalidateCount by mutableIntStateOf(0)
- @Composable
- internal fun RenderVector(
- name: String,
- viewportWidth: Float,
- viewportHeight: Float,
- content: @Composable (viewportWidth: Float, viewportHeight: Float) -> Unit
- ) {
- vector.apply {
- this.name = name
- this.viewportWidth = viewportWidth
- this.viewportHeight = viewportHeight
- }
- val composition = composeVector(
- rememberCompositionContext(),
- content
- )
-
- DisposableEffect(composition) {
- onDispose {
- composition.dispose()
- }
- }
- }
-
private var currentAlpha: Float = 1.0f
private var currentColorFilter: ColorFilter? = null
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
index ba4ee3b..1d331e9 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/LookaheadScope.kt
@@ -44,7 +44,6 @@
*
* @param content The child composable to be laid out.
*/
-@ExperimentalComposeUiApi
@UiComposable
@Composable
fun LookaheadScope(content: @Composable @UiComposable LookaheadScope.() -> Unit) {
@@ -145,18 +144,19 @@
*
* @sample androidx.compose.ui.samples.LookaheadLayoutCoordinatesSample
*/
-@ExperimentalComposeUiApi
interface LookaheadScope {
/**
* Converts a [LayoutCoordinates] into a [LayoutCoordinates] in the Lookahead coordinates space.
* This is only applicable to child layouts within [LookaheadScope].
*/
+ @ExperimentalComposeUiApi
fun LayoutCoordinates.toLookaheadCoordinates(): LayoutCoordinates
/**
* Returns the [LayoutCoordinates] of the [LookaheadScope]. This is
* only accessible from [Placeable.PlacementScope] (i.e. during placement time).
*/
+ @ExperimentalComposeUiApi
val Placeable.PlacementScope.lookaheadScopeCoordinates: LayoutCoordinates
/**
@@ -165,6 +165,7 @@
* [toLookaheadCoordinates], and 2) invoking [LayoutCoordinates.localPositionOf] with the
* converted coordinates.
*/
+ @ExperimentalComposeUiApi
fun LayoutCoordinates.localLookaheadPositionOf(coordinates: LayoutCoordinates) =
this.toLookaheadCoordinates().localPositionOf(
coordinates.toLookaheadCoordinates(),
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index c55e1d35..e09adc6 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -735,6 +735,13 @@
get() = measurePassDelegate.isPlaced
/**
+ * Whether or not this [LayoutNode] was placed by its parent. The node can still be considered
+ * not placed if some of the modifiers on it not placed the placeable.
+ */
+ val isPlacedByParent: Boolean
+ get() = measurePassDelegate.isPlacedByParent
+
+ /**
* The order in which this node was placed by its parent during the previous `layoutChildren`.
* Before the placement the order is set to [NotPlacedPlaceOrder] to all the children. Then
* every placed node assigns this variable to [parent]s MeasurePassDelegate's
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
index 75aaace..3abc4d9 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeLayoutDelegate.kt
@@ -318,6 +318,8 @@
*/
override var isPlaced: Boolean = false
internal set
+ var isPlacedByParent: Boolean = false
+ internal set
override val innerCoordinator: NodeCoordinator
get() = layoutNode.innerCoordinator
override val alignmentLines: AlignmentLines = LayoutNodeAlignmentLines(this)
@@ -459,10 +461,13 @@
internal var zIndex: Float = 0f
private set
+ private var onNodePlacedCalled = false
+
/**
* Invoked when the parent placed the node. It will trigger the layout.
*/
internal fun onNodePlaced() {
+ onNodePlacedCalled = true
val parent = layoutNode.parent
var newZIndex = innerCoordinator.zIndex
@@ -480,6 +485,11 @@
// parents inner layer - the layer in which this child will be drawn
parent?.invalidateLayer()
markNodeAndSubtreeAsPlaced()
+ if (relayoutWithoutParentInProgress) {
+ // this node wasn't placed previously and the parent thinks this node is not
+ // visible, so we need to relayout the parent to get the `placeOrder`.
+ parent?.requestRelayout()
+ }
}
if (parent != null) {
@@ -511,6 +521,7 @@
// and reset the place order for all the children before placing them
child.previousPlaceOrder = child.placeOrder
child.placeOrder = NotPlacedPlaceOrder
+ child.isPlacedByParent = false
// before rerunning the user's layout block reset previous measuredByParent
// for children which we measured in the layout block during the last run.
if (child.measuredByParent == LayoutNode.UsageByParent.InLayoutBlock) {
@@ -637,6 +648,7 @@
zIndex: Float,
layerBlock: (GraphicsLayerScope.() -> Unit)?
) {
+ isPlacedByParent = true
if (position != lastPosition) {
if (coordinatesAccessedDuringModifierPlacement ||
coordinatesAccessedDuringPlacement) {
@@ -678,6 +690,7 @@
lastZIndex = zIndex
lastLayerBlock = layerBlock
placedOnce = true
+ onNodePlacedCalled = false
val owner = layoutNode.requireOwner()
if (!layoutPending && isPlaced) {
@@ -711,7 +724,13 @@
try {
relayoutWithoutParentInProgress = true
check(placedOnce) { "replace called on unplaced item" }
+ val wasPlacedBefore = isPlaced
placeOuterCoordinator(lastPosition, lastZIndex, lastLayerBlock)
+ if (wasPlacedBefore && !onNodePlacedCalled) {
+ // parent should be notified that this node is not placed anymore so the
+ // children `placeOrder`s are updated.
+ layoutNode.parent?.requestRelayout()
+ }
} finally {
relayoutWithoutParentInProgress = false
}
@@ -1244,6 +1263,7 @@
) {
layoutState = LayoutState.LookaheadLayingOut
placedOnce = true
+ onNodePlacedCalled = false
if (position != lastPosition) {
if (coordinatesAccessedDuringModifierPlacement ||
coordinatesAccessedDuringPlacement) {
@@ -1254,6 +1274,7 @@
val owner = layoutNode.requireOwner()
if (!lookaheadLayoutPending && isPlaced) {
+ outerCoordinator.lookaheadDelegate!!.placeSelfApparentToRealOffset(position)
onNodePlaced()
} else {
coordinatesAccessedDuringModifierPlacement = false
@@ -1381,10 +1402,18 @@
return true
}
+ private var onNodePlacedCalled = false
+
internal fun onNodePlaced() {
+ onNodePlacedCalled = true
val parent = layoutNode.parent
if (!isPlaced) {
markNodeAndSubtreeAsPlaced()
+ if (relayoutWithoutParentInProgress) {
+ // this node wasn't placed previously and the parent thinks this node is not
+ // visible, so we need to relayout the parent to get the `placeOrder`.
+ parent?.requestLookaheadRelayout()
+ }
}
if (parent != null) {
if (!relayoutWithoutParentInProgress &&
@@ -1484,7 +1513,15 @@
try {
relayoutWithoutParentInProgress = true
check(placedOnce) { "replace() called on item that was not placed" }
+
+ onNodePlacedCalled = false
+ val wasPlacedBefore = isPlaced
placeAt(lastPosition, 0f, null)
+ if (wasPlacedBefore && !onNodePlacedCalled) {
+ // parent should be notified that this node is not placed anymore so the
+ // children `placeOrder`s are updated.
+ layoutNode.parent?.requestLookaheadRelayout()
+ }
} finally {
relayoutWithoutParentInProgress = false
}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt
index ba59c04..42c7d6b5 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LookaheadDelegate.kt
@@ -151,14 +151,22 @@
zIndex: Float,
layerBlock: (GraphicsLayerScope.() -> Unit)?
) {
+ placeSelf(position)
+ if (isShallowPlacing) return
+ placeChildren()
+ }
+
+ private fun placeSelf(position: IntOffset) {
if (this.position != position) {
this.position = position
layoutNode.layoutDelegate.lookaheadPassDelegate
?.notifyChildrenUsingCoordinatesWhilePlacing()
coordinator.invalidateAlignmentLinesFromPositionChange()
}
- if (isShallowPlacing) return
- placeChildren()
+ }
+
+ internal fun placeSelfApparentToRealOffset(position: IntOffset) {
+ placeSelf(position + apparentToRealOffset)
}
protected open fun placeChildren() {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
index a4c270d..9c53aa8 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
@@ -154,12 +154,16 @@
} else {
layoutNode.markLookaheadMeasurePending()
layoutNode.markMeasurePending()
- if (layoutNode.isPlacedInLookahead == true ||
- layoutNode.canAffectParentInLookahead
+ if ((layoutNode.isPlacedInLookahead == true ||
+ layoutNode.canAffectParentInLookahead) &&
+ layoutNode.parent?.lookaheadMeasurePending != true
) {
- if (layoutNode.parent?.lookaheadMeasurePending != true) {
- relayoutNodes.add(layoutNode, true)
- }
+ relayoutNodes.add(layoutNode, true)
+ } else if (
+ (layoutNode.isPlaced || layoutNode.canAffectParent) &&
+ layoutNode.parent?.measurePending != true
+ ) {
+ relayoutNodes.add(layoutNode, false)
}
!duringMeasureLayout
}
@@ -238,13 +242,17 @@
// dependency on lookahead layout.
layoutNode.markLookaheadLayoutPending()
layoutNode.markLayoutPending()
- if (layoutNode.isPlacedInLookahead == true) {
- val parent = layoutNode.parent
- if (parent?.lookaheadMeasurePending != true &&
- parent?.lookaheadLayoutPending != true
- ) {
- relayoutNodes.add(layoutNode, true)
- }
+
+ val parent = layoutNode.parent
+ if (layoutNode.isPlacedInLookahead == true &&
+ parent?.lookaheadMeasurePending != true &&
+ parent?.lookaheadLayoutPending != true
+ ) {
+ relayoutNodes.add(layoutNode, true)
+ } else if (layoutNode.isPlaced &&
+ parent?.layoutPending != true && parent?.measurePending != true
+ ) {
+ relayoutNodes.add(layoutNode, false)
}
!duringMeasureLayout
}
@@ -462,7 +470,7 @@
) {
layoutNode.lookaheadReplace()
}
- if (layoutNode.layoutPending && layoutNode.isPlaced) {
+ if (layoutNode.layoutPending && (layoutNode.isPlacedByParent || layoutNode === root)) {
if (layoutNode === root) {
layoutNode.place(0, 0)
} else {
diff --git a/constraintlayout/constraintlayout-core/lint-baseline.xml b/constraintlayout/constraintlayout-core/lint-baseline.xml
index bff62dd..1c3b73f 100644
--- a/constraintlayout/constraintlayout-core/lint-baseline.xml
+++ b/constraintlayout/constraintlayout-core/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
+<issues format="6" by="lint 8.1.0" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0)" variant="all" version="8.1.0">
<issue
id="PrivateConstructorForUtilityClass"
@@ -74,645 +74,6 @@
</issue>
<issue
- id="SyntheticAccessor"
- message="Access to `private` field `mId` of class `Constraint` requires synthetic accessor"
- errorLine1=" return mId;"
- errorLine2=" ~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/dsl/Constraint.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" return mWidth - mHorizontalGap;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" return mHeight - mVerticalGap;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getWidgetWidth` of class `Flow` requires synthetic accessor"
- errorLine1=" int width = getWidgetWidth(widget, mMax);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" int gap = mHorizontalGap;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getWidgetHeight` of class `Flow` requires synthetic accessor"
- errorLine1=" int height = getWidgetHeight(widget, mMax);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getWidgetWidth` of class `Flow` requires synthetic accessor"
- errorLine1=" int width = getWidgetWidth(widget, mMax);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getWidgetHeight` of class `Flow` requires synthetic accessor"
- errorLine1=" int height = getWidgetHeight(widget, mMax);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" int gap = mVerticalGap;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgetsCount` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex + i >= mDisplayedWidgetsCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgets` of class `Flow` requires synthetic accessor"
- errorLine1=" ConstraintWidget widget = mDisplayedWidgets[mStartIndex + i];"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgetsCount` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex + index >= mDisplayedWidgetsCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgets` of class `Flow` requires synthetic accessor"
- errorLine1=" ConstraintWidget widget = mDisplayedWidgets[mStartIndex + index];"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" verticalWidget.setVerticalChainStyle(mVerticalStyle);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" padding += mVerticalGap;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalAlign` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mVerticalAlign == VERTICAL_ALIGN_BASELINE && !verticalWidget.hasBaseline()) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgetsCount` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex + index >= mDisplayedWidgetsCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgets` of class `Flow` requires synthetic accessor"
- errorLine1=" ConstraintWidget widget = mDisplayedWidgets[mStartIndex + index];"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgetsCount` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex + index >= mDisplayedWidgetsCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgets` of class `Flow` requires synthetic accessor"
- errorLine1=" ConstraintWidget widget = mDisplayedWidgets[mStartIndex + index];"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" int style = mHorizontalStyle;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" float bias = isInRtl ? (1 - mHorizontalBias) : mHorizontalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" float bias = isInRtl ? (1 - mHorizontalBias) : mHorizontalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFirstHorizontalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex == 0 && mFirstHorizontalStyle != UNKNOWN) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFirstHorizontalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" style = mFirstHorizontalStyle;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFirstHorizontalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" bias = isInRtl ? (1 - mFirstHorizontalBias) : mFirstHorizontalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFirstHorizontalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" bias = isInRtl ? (1 - mFirstHorizontalBias) : mFirstHorizontalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastHorizontalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" } else if (isLastChain && mLastHorizontalStyle != UNKNOWN) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastHorizontalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" style = mLastHorizontalStyle;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastHorizontalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" bias = isInRtl ? (1 - mLastHorizontalBias) : mLastHorizontalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastHorizontalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" bias = isInRtl ? (1 - mLastHorizontalBias) : mLastHorizontalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" widget.mLeft.connect(previous.mRight, mHorizontalGap);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalAlign` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mVerticalAlign == VERTICAL_ALIGN_BASELINE"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalAlign` of class `Flow` requires synthetic accessor"
- errorLine1=" switch (mVerticalAlign) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" horizontalWidget.setHorizontalChainStyle(mHorizontalStyle);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" padding += mHorizontalGap;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgetsCount` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex + i >= mDisplayedWidgetsCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgets` of class `Flow` requires synthetic accessor"
- errorLine1=" ConstraintWidget widget = mDisplayedWidgets[mStartIndex + i];"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" int style = mVerticalStyle;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" float bias = mVerticalBias;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFirstVerticalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex == 0 && mFirstVerticalStyle != UNKNOWN) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFirstVerticalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" style = mFirstVerticalStyle;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFirstVerticalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" bias = mFirstVerticalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastVerticalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" } else if (isLastChain && mLastVerticalStyle != UNKNOWN) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastVerticalStyle` of class `Flow` requires synthetic accessor"
- errorLine1=" style = mLastVerticalStyle;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastVerticalBias` of class `Flow` requires synthetic accessor"
- errorLine1=" bias = mLastVerticalBias;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" widget.mTop.connect(previous.mBottom, mVerticalGap);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalAlign` of class `Flow` requires synthetic accessor"
- errorLine1=" switch (mHorizontalAlign) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalAlign` of class `Flow` requires synthetic accessor"
- errorLine1=" switch (mHorizontalAlign) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgetsCount` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex + i >= mDisplayedWidgetsCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgets` of class `Flow` requires synthetic accessor"
- errorLine1=" ConstraintWidget widget = mDisplayedWidgets[mStartIndex + i];"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgetsCount` of class `Flow` requires synthetic accessor"
- errorLine1=" if (mStartIndex + i >= mDisplayedWidgetsCount) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisplayedWidgets` of class `Flow` requires synthetic accessor"
- errorLine1=" ConstraintWidget widget = mDisplayedWidgets[mStartIndex + i];"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mHorizontalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" int gap = mHorizontalGap;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getWidgetHeight` of class `Flow` requires synthetic accessor"
- errorLine1=" int height = getWidgetHeight(widget, mMax);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getWidgetWidth` of class `Flow` requires synthetic accessor"
- errorLine1=" int width = getWidgetWidth(widget, mMax);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getWidgetHeight` of class `Flow` requires synthetic accessor"
- errorLine1=" int height = getWidgetHeight(widget, mMax);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVerticalGap` of class `Flow` requires synthetic accessor"
- errorLine1=" int gap = mVerticalGap;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" && list.mBiggest != null;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" && list.mBiggest != null;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" bottom = next.mBiggest.mTop;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" ConstraintAnchor currentBottom = current.mBiggest.mBottom;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" right = next.mBiggest.mLeft;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" ConstraintAnchor currentRight = current.mBiggest.mRight;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" && list.mBiggest != null;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" && list.mBiggest != null;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" bottom = next.mBiggest.mTop;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" ConstraintAnchor currentBottom = current.mBiggest.mBottom;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" right = next.mBiggest.mLeft;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBiggest` of class `WidgetsList` requires synthetic accessor"
- errorLine1=" ConstraintAnchor currentRight = current.mBiggest.mRight;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/widgets/Flow.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `removeGoal` of class `PriorityGoalRow` requires synthetic accessor"
- errorLine1=" removeGoal(mVariable);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/core/PriorityGoalRow.java"/>
- </issue>
-
- <issue
id="KotlinPropertyAccess"
message="The getter return type (`CLElement`) and setter parameter type (`CLContainer`) getter and setter methods for property `container` should have exactly the same type to allow be accessed as a property from Kotlin; see https://android.github.io/kotlin-guides/interop.html#property-prefixes"
errorLine1=" public CLElement getContainer() {"
diff --git a/constraintlayout/constraintlayout/lint-baseline.xml b/constraintlayout/constraintlayout/lint-baseline.xml
index a9b5204..03b1210 100644
--- a/constraintlayout/constraintlayout/lint-baseline.xml
+++ b/constraintlayout/constraintlayout/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-alpha07" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-alpha07)" variant="all" version="8.0.0-alpha07">
+<issues format="6" by="lint 8.1.0" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0)" variant="all" version="8.1.0">
<issue
id="NewApi"
@@ -1118,3138 +1118,6 @@
</issue>
<issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `Carousel` requires synthetic accessor"
- errorLine1=" mMotionLayout.setProgress(0);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `updateItems` of class `Carousel` requires synthetic accessor"
- errorLine1=" updateItems();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAdapter` of class `Carousel` requires synthetic accessor"
- errorLine1=" mAdapter.onNewItem(mIndex);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" mAdapter.onNewItem(mIndex);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `Carousel` requires synthetic accessor"
- errorLine1=" float velocity = mMotionLayout.getVelocity();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchUpMode` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mTouchUpMode == TOUCH_UP_CARRY_ON && velocity > mVelocityThreshold"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mVelocityThreshold` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mTouchUpMode == TOUCH_UP_CARRY_ON && velocity > mVelocityThreshold"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAdapter` of class `Carousel` requires synthetic accessor"
- errorLine1=" && mIndex < mAdapter.count() - 1) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" && mIndex < mAdapter.count() - 1) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDampening` of class `Carousel` requires synthetic accessor"
- errorLine1=" final float v = velocity * mDampening;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mIndex == 0 && mPreviousIndex > mIndex) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mIndex == 0 && mPreviousIndex > mIndex) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPreviousIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mIndex == 0 && mPreviousIndex > mIndex) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAdapter` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mIndex == mAdapter.count() - 1 && mPreviousIndex < mIndex) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mIndex == mAdapter.count() - 1 && mPreviousIndex < mIndex) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mIndex == mAdapter.count() - 1 && mPreviousIndex < mIndex) {"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPreviousIndex` of class `Carousel` requires synthetic accessor"
- errorLine1=" if (mIndex == mAdapter.count() - 1 && mPreviousIndex < mIndex) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `Carousel` requires synthetic accessor"
- errorLine1=" mMotionLayout.post(new Runnable() {"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `Carousel` requires synthetic accessor"
- errorLine1=" mMotionLayout.touchAnimateTo(MotionLayout.TOUCH_UP_DECELERATE_AND_COMPLETE,"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/helper/widget/Carousel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMetrics` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" if (mMetrics != null) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMetrics` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" mMetrics.mNumberOfMeasures++;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOptimizationLevel` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" if (container != null && Optimizer.enabled(mOptimizationLevel,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOptimizationLevel` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" boolean optimizeDirect = Optimizer.enabled(mOptimizationLevel,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMetrics` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" if (mMetrics != null) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMetrics` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" mMetrics.measuresWidgetsDuration += (endMeasure - startMeasure);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintHelpers` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" final int helperCount = mLayout.mConstraintHelpers.size();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintHelpers` of class `ConstraintLayout` requires synthetic accessor"
- errorLine1=" ConstraintHelper helper = mLayout.mConstraintHelpers.get(i);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `fillFrom` of class `Constraint` requires synthetic accessor"
- errorLine1=" constraint.fillFrom(id, param);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" leftToLeft = lookupID(a, attr, leftToLeft);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" leftToRight = lookupID(a, attr, leftToRight);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" rightToLeft = lookupID(a, attr, rightToLeft);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" rightToRight = lookupID(a, attr, rightToRight);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" topToTop = lookupID(a, attr, topToTop);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" topToBottom = lookupID(a, attr, topToBottom);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" bottomToTop = lookupID(a, attr, bottomToTop);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" bottomToBottom = lookupID(a, attr, bottomToBottom);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" baselineToBaseline = lookupID(a, attr, baselineToBaseline);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" baselineToTop = lookupID(a, attr, baselineToTop);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" baselineToBottom = lookupID(a, attr, baselineToBottom);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" startToEnd = lookupID(a, attr, startToEnd);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" startToStart = lookupID(a, attr, startToStart);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" endToStart = lookupID(a, attr, endToStart);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" endToEnd = lookupID(a, attr, endToEnd);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" circleConstraint = lookupID(a, attr, circleConstraint);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" transformPivotTarget = lookupID(a, attr, transformPivotTarget);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `lookupID` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" mAnimateRelativeTo = lookupID(a, attr, mAnimateRelativeTo);"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setDeltaValue` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" setDeltaValue(c, mTypeInt[i], mValueInt[i]);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setDeltaValue` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" setDeltaValue(c, mTypeFloat[i], mValueFloat[i]);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setDeltaValue` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" setDeltaValue(c, mTypeString[i], mValueString[i]);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setDeltaValue` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" setDeltaValue(c, mTypeBoolean[i], mValueBoolean[i]);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `fillFrom` of class `Constraint` requires synthetic accessor"
- errorLine1=" constraint.fillFrom(id, param);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `fillFromConstraints` of class `Constraint` requires synthetic accessor"
- errorLine1=" constraint.fillFromConstraints(helper, id, param);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `fillFromConstraints` of class `Constraint` requires synthetic accessor"
- errorLine1=" constraint.fillFromConstraints(id, param);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setIntValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" get(viewId).setIntValue(attributeName, value);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setColorValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" get(viewId).setColorValue(attributeName, value);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setFloatValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" get(viewId).setFloatValue(attributeName, value);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setStringValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" get(viewId).setStringValue(attributeName, value);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setFloatValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" set.setFloatValue(attr[0], Integer.decode(attr[1]));"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setColorValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" set.setColorValue(attr[0], Color.parseColor(attr[1]));"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setFloatValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" set.setFloatValue(attr[0], Float.parseFloat(attr[1]));"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setStringValue` of class `Constraint` requires synthetic accessor"
- errorLine1=" set.setStringValue(attr[0], attr[1]);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraints` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" for (Integer id : mConstraints.keySet()) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraints` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" Constraint c = mConstraints.get(id);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraints` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" for (Integer id : mConstraints.keySet()) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraints` of class `ConstraintSet` requires synthetic accessor"
- errorLine1=" Constraint c = mConstraints.get(id);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/widget/ConstraintSet.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRoundPercent` of class `ImageFilterButton` requires synthetic accessor"
- errorLine1=" float r = Math.min(w, h) * mRoundPercent / 2;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/ImageFilterButton.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRound` of class `ImageFilterButton` requires synthetic accessor"
- errorLine1=" outline.setRoundRect(0, 0, w, h, mRound);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/ImageFilterButton.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRoundPercent` of class `ImageFilterView` requires synthetic accessor"
- errorLine1=" float r = Math.min(w, h) * mRoundPercent / 2;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/ImageFilterView.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRound` of class `ImageFilterView` requires synthetic accessor"
- errorLine1=" outline.setRoundRect(0, 0, w, h, mRound);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/ImageFilterView.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAlpha` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mAlpha = a.getFloat(attr, c.mAlpha);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAlpha` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mAlpha = a.getFloat(attr, c.mAlpha);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mElevation` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mElevation = a.getDimension(attr, c.mElevation);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mElevation` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mElevation = a.getDimension(attr, c.mElevation);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotation` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mRotation = a.getFloat(attr, c.mRotation);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotation` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mRotation = a.getFloat(attr, c.mRotation);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCurveFit` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mCurveFit = a.getInteger(attr, c.mCurveFit);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCurveFit` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mCurveFit = a.getInteger(attr, c.mCurveFit);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mScaleX = a.getFloat(attr, c.mScaleX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mScaleX = a.getFloat(attr, c.mScaleX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mRotationX = a.getFloat(attr, c.mRotationX);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mRotationX = a.getFloat(attr, c.mRotationX);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mRotationY = a.getFloat(attr, c.mRotationY);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mRotationY = a.getFloat(attr, c.mRotationY);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPivotX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mPivotX = a.getDimension(attr, c.mPivotX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPivotX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mPivotX = a.getDimension(attr, c.mPivotX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPivotY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mPivotY = a.getDimension(attr, c.mPivotY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPivotY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mPivotY = a.getDimension(attr, c.mPivotY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionEasing` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTransitionEasing = a.getString(attr);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mScaleY = a.getFloat(attr, c.mScaleY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mScaleY = a.getFloat(attr, c.mScaleY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionPathRotate` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTransitionPathRotate = a.getFloat(attr, c.mTransitionPathRotate);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionPathRotate` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTransitionPathRotate = a.getFloat(attr, c.mTransitionPathRotate);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTranslationX = a.getDimension(attr, c.mTranslationX);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationX` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTranslationX = a.getDimension(attr, c.mTranslationX);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTranslationY = a.getDimension(attr, c.mTranslationY);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationY` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTranslationY = a.getDimension(attr, c.mTranslationY);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationZ` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTranslationZ = a.getDimension(attr, c.mTranslationZ);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationZ` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mTranslationZ = a.getDimension(attr, c.mTranslationZ);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mProgress` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mProgress = a.getFloat(attr, c.mProgress);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mProgress` of class `KeyAttributes` requires synthetic accessor"
- errorLine1=" c.mProgress = a.getFloat(attr, c.mProgress);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyAttributes.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `read` of class `Loader` requires synthetic accessor"
- errorLine1=" Loader.read(this, a);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionEasing` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTransitionEasing = a.getString(attr);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCurveFit` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mCurveFit = a.getInteger(attr, c.mCurveFit);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCurveFit` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mCurveFit = a.getInteger(attr, c.mCurveFit);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCustomWaveShape` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mCustomWaveShape = a.getString(attr);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveShape` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveShape = Oscillator.CUSTOM;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveShape` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveShape = a.getInt(attr, c.mWaveShape);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveShape` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveShape = a.getInt(attr, c.mWaveShape);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWavePeriod` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWavePeriod = a.getFloat(attr, c.mWavePeriod);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWavePeriod` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWavePeriod = a.getFloat(attr, c.mWavePeriod);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getDimension(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getDimension(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getFloat(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getFloat(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveVariesBy` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveVariesBy = a.getInt(attr, c.mWaveVariesBy);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveVariesBy` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWaveVariesBy = a.getInt(attr, c.mWaveVariesBy);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAlpha` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mAlpha = a.getFloat(attr, c.mAlpha);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAlpha` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mAlpha = a.getFloat(attr, c.mAlpha);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mElevation` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mElevation = a.getDimension(attr, c.mElevation);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mElevation` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mElevation = a.getDimension(attr, c.mElevation);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotation` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mRotation = a.getFloat(attr, c.mRotation);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotation` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mRotation = a.getFloat(attr, c.mRotation);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationX` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mRotationX = a.getFloat(attr, c.mRotationX);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationX` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mRotationX = a.getFloat(attr, c.mRotationX);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationY` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mRotationY = a.getFloat(attr, c.mRotationY);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationY` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mRotationY = a.getFloat(attr, c.mRotationY);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionPathRotate` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTransitionPathRotate = a.getFloat(attr, c.mTransitionPathRotate);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionPathRotate` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTransitionPathRotate = a.getFloat(attr, c.mTransitionPathRotate);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleX` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mScaleX = a.getFloat(attr, c.mScaleX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleX` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mScaleX = a.getFloat(attr, c.mScaleX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleY` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mScaleY = a.getFloat(attr, c.mScaleY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleY` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mScaleY = a.getFloat(attr, c.mScaleY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationX` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationX = a.getDimension(attr, c.mTranslationX);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationX` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationX = a.getDimension(attr, c.mTranslationX);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationY` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationY = a.getDimension(attr, c.mTranslationY);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationY` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationY = a.getDimension(attr, c.mTranslationY);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationZ` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationZ = a.getDimension(attr, c.mTranslationZ);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationZ` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationZ = a.getDimension(attr, c.mTranslationZ);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mProgress` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mProgress = a.getFloat(attr, c.mProgress);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mProgress` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mProgress = a.getFloat(attr, c.mProgress);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWavePhase` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWavePhase = a.getFloat(attr, c.mWavePhase) / 360;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWavePhase` of class `KeyCycle` requires synthetic accessor"
- errorLine1=" c.mWavePhase = a.getFloat(attr, c.mWavePhase) / 360;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `read` of class `Loader` requires synthetic accessor"
- errorLine1=" Loader.read(this, a);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyPosition.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAlpha` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mAlpha = a.getFloat(attr, c.mAlpha);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAlpha` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mAlpha = a.getFloat(attr, c.mAlpha);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mElevation` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mElevation = a.getDimension(attr, c.mElevation);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mElevation` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mElevation = a.getDimension(attr, c.mElevation);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotation` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mRotation = a.getFloat(attr, c.mRotation);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotation` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mRotation = a.getFloat(attr, c.mRotation);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCurveFit` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mCurveFit = a.getInteger(attr, c.mCurveFit);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCurveFit` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mCurveFit = a.getInteger(attr, c.mCurveFit);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCustomWaveShape` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mCustomWaveShape = a.getString(attr);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveShape` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWaveShape = Oscillator.CUSTOM;"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveShape` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWaveShape = a.getInt(attr, c.mWaveShape);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveShape` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWaveShape = a.getInt(attr, c.mWaveShape);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWavePeriod` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWavePeriod = a.getFloat(attr, c.mWavePeriod);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWavePeriod` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWavePeriod = a.getFloat(attr, c.mWavePeriod);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getDimension(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getDimension(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getFloat(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mWaveOffset` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mWaveOffset = a.getFloat(attr, c.mWaveOffset);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleX` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mScaleX = a.getFloat(attr, c.mScaleX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleX` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mScaleX = a.getFloat(attr, c.mScaleX);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationX` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mRotationX = a.getFloat(attr, c.mRotationX);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationX` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mRotationX = a.getFloat(attr, c.mRotationX);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationY` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mRotationY = a.getFloat(attr, c.mRotationY);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRotationY` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mRotationY = a.getFloat(attr, c.mRotationY);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionEasing` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTransitionEasing = a.getString(attr);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleY` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mScaleY = a.getFloat(attr, c.mScaleY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mScaleY` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mScaleY = a.getFloat(attr, c.mScaleY);"
- errorLine2=" ~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionPathRotate` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTransitionPathRotate = a.getFloat(attr, c.mTransitionPathRotate);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTransitionPathRotate` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTransitionPathRotate = a.getFloat(attr, c.mTransitionPathRotate);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationX` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationX = a.getDimension(attr, c.mTranslationX);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationX` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationX = a.getDimension(attr, c.mTranslationX);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationY` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationY = a.getDimension(attr, c.mTranslationY);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationY` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationY = a.getDimension(attr, c.mTranslationY);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationZ` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationZ = a.getDimension(attr, c.mTranslationZ);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTranslationZ` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mTranslationZ = a.getDimension(attr, c.mTranslationZ);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mProgress` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mProgress = a.getFloat(attr, c.mProgress);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mProgress` of class `KeyTimeCycle` requires synthetic accessor"
- errorLine1=" c.mProgress = a.getFloat(attr, c.mProgress);"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTimeCycle.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mFireThreshold` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mFireThreshold = (c.mFramePosition + .5f) / 100f;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mNegativeCross` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mNegativeCross = a.getString(attr);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPositiveCross` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mPositiveCross = a.getString(attr);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCross` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mCross = a.getString(attr);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTriggerID` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mTriggerID = a.getResourceId(attr, c.mTriggerID);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTriggerID` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mTriggerID = a.getResourceId(attr, c.mTriggerID);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTriggerCollisionId` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mTriggerCollisionId = a.getResourceId(attr, c.mTriggerCollisionId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTriggerCollisionId` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mTriggerCollisionId = a.getResourceId(attr, c.mTriggerCollisionId);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPostLayout` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mPostLayout = a.getBoolean(attr, c.mPostLayout);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPostLayout` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mPostLayout = a.getBoolean(attr, c.mPostLayout);"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTriggerReceiver` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mTriggerReceiver = a.getResourceId(attr, c.mTriggerReceiver);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTriggerReceiver` of class `KeyTrigger` requires synthetic accessor"
- errorLine1=" c.mTriggerReceiver = a.getResourceId(attr, c.mTriggerReceiver);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/KeyTrigger.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRoundPercent` of class `MotionButton` requires synthetic accessor"
- errorLine1=" float r = Math.min(w, h) * mRoundPercent / 2;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/MotionButton.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRound` of class `MotionButton` requires synthetic accessor"
- errorLine1=" outline.setRoundRect(0, 0, w, h, mRound);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/MotionButton.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRoundPercent` of class `MotionLabel` requires synthetic accessor"
- errorLine1=" float r = Math.min(w, h) * mRoundPercent / 2;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/MotionLabel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mRound` of class `MotionLabel` requires synthetic accessor"
- errorLine1=" outline.setRoundRect(0, 0, w, h, mRound);"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/utils/widget/MotionLabel.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mStateCache` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" mStateCache.apply();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mEndState` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" mEndState = MotionLayout.this.mEndState;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mBeginState` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" mStartState = MotionLayout.this.mBeginState;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mInRotation` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" mInRotation = false;"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastHeightMeasureSpec` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLastWidthMeasureSpec` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `setupMotionViews` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" setupMotionViews();"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `toRect` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" motionController.setStartState(toRect(startWidget), mStart,"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mInRotation` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" if (mInRotation) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPreRotateHeight` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" mPreRotateWidth, mPreRotateHeight);"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPreRotateWidth` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" mPreRotateWidth, mPreRotateHeight);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `toRect` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" motionController.setEndState(toRect(endWidget), mEnd,"
- errorLine2=" ~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mEndState` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" String str = getContext().getResources().getResourceName(mEndState)"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mStateCache` of class `MotionLayout` requires synthetic accessor"
- errorLine1=" mStateCache.apply();"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition.mConstraintSetEnd == endId"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" && mCurrentTransition.mConstraintSetStart == beginId) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" if ((transition.mConstraintSetEnd == end"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" && transition.mConstraintSetStart == start)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" || (transition.mConstraintSetEnd == endId"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" && transition.mConstraintSetStart == beginId)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.setRTL(mRtl);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mConstraintSetEnd == endId) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" t.mConstraintSetStart = start;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" t.mConstraintSetEnd = end;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mId` of class `Transition` requires synthetic accessor"
- errorLine1=" int id = transition.mId;"
- errorLine2=" ~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mId` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mTransitionList.get(index).mId == id) {"
- errorLine2=" ~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.setRTL(mRtl);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mConstraintSetStart == stateId"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" || transition.mConstraintSetEnd == stateId) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mOnClicks.size() > 0) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" for (Transition.TransitionOnClick onClick : transition.mOnClicks) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mOnClicks.size() > 0) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" for (Transition.TransitionOnClick onClick : transition.mOnClicks) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mOnClicks.size() > 0) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" for (Transition.TransitionOnClick onClick : transition.mOnClicks) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mOnClicks.size() > 0) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mOnClicks` of class `Transition` requires synthetic accessor"
- errorLine1=" for (Transition.TransitionOnClick onClick : transition.mOnClicks) {"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDisable` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mDisable) {"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" transition.mTouchResponse.setRTL(mRtl);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" RectF region = transition.mTouchResponse.getTouchRegion(mMotionLayout, cache);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" region = transition.mTouchResponse.getLimitBoundsTo(mMotionLayout, cache);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" float val = transition.mTouchResponse.dot(dx, dy);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mTouchResponse.mIsRotateMode && lastTouchDown != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" - transition.mTouchResponse.mRotateCenterX;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" - transition.mTouchResponse.mRotateCenterY;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mConstraintSetEnd == currentState) { // flip because backwards"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mId` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mId == id) {"
- errorLine2=" ~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAutoTransition` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mAutoTransition == Transition.AUTO_NONE) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" if (currentState == transition.mConstraintSetStart && ("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAutoTransition` of class `Transition` requires synthetic accessor"
- errorLine1=" transition.mAutoTransition == Transition.AUTO_ANIMATE_TO_END"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAutoTransition` of class `Transition` requires synthetic accessor"
- errorLine1=" || transition.mAutoTransition == Transition.AUTO_JUMP_TO_END)) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAutoTransition` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mAutoTransition == Transition.AUTO_ANIMATE_TO_END) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" if (currentState == transition.mConstraintSetEnd && ("
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAutoTransition` of class `Transition` requires synthetic accessor"
- errorLine1=" transition.mAutoTransition == Transition.AUTO_ANIMATE_TO_START"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAutoTransition` of class `Transition` requires synthetic accessor"
- errorLine1=" || transition.mAutoTransition == Transition.AUTO_JUMP_TO_START)) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mAutoTransition` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mAutoTransition == Transition.AUTO_ANIMATE_TO_START) {"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.setRTL(mRtl);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `MotionScene` requires synthetic accessor"
- errorLine1=" : new TouchResponse(mMotionScene.mMotionLayout, onSwipe);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" int start = transition.mConstraintSetStart;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" int end = transition.mConstraintSetEnd;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" int dest = mTransition.mConstraintSetEnd;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" int from = mTransition.mConstraintSetStart;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `MotionScene` requires synthetic accessor"
- errorLine1=" MotionLayout tl = mTransition.mMotionScene.mMotionLayout;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionScene` of class `Transition` requires synthetic accessor"
- errorLine1=" MotionLayout tl = mTransition.mMotionScene.mMotionLayout;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mTransition.mConstraintSetStart == UNSET) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" tl.transitionToState(mTransition.mConstraintSetEnd);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionScene` of class `Transition` requires synthetic accessor"
- errorLine1=" Transition t = new Transition(mTransition.mMotionScene, mTransition);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" t.mConstraintSetStart = currentState;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" t.mConstraintSetEnd = mTransition.mConstraintSetEnd;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" t.mConstraintSetEnd = mTransition.mConstraintSetEnd;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionScene` of class `Transition` requires synthetic accessor"
- errorLine1=" Transition current = mTransition.mMotionScene.mCurrentTransition;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionScene` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mTransition.mMotionScene.mCurrentTransition != mTransition) {"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDefaultDuration` of class `MotionScene` requires synthetic accessor"
- errorLine1=" mDuration = motionScene.mDefaultDuration;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDefaultDuration` of class `MotionScene` requires synthetic accessor"
- errorLine1=" mDuration = motionScene.mDefaultDuration;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLayoutDuringTransition` of class `MotionScene` requires synthetic accessor"
- errorLine1=" mLayoutDuringTransition = motionScene.mLayoutDuringTransition;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDefaultDuration` of class `MotionScene` requires synthetic accessor"
- errorLine1=" mDuration = motionScene.mDefaultDuration;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mLayoutDuringTransition` of class `MotionScene` requires synthetic accessor"
- errorLine1=" mLayoutDuringTransition = motionScene.mLayoutDuringTransition;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetMap` of class `MotionScene` requires synthetic accessor"
- errorLine1=" motionScene.mConstraintSetMap.append(mConstraintSetEnd, cSet);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `parseInclude` of class `MotionScene` requires synthetic accessor"
- errorLine1=" int id = motionScene.parseInclude(context, mConstraintSetEnd);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetMap` of class `MotionScene` requires synthetic accessor"
- errorLine1=" motionScene.mConstraintSetMap.append(mConstraintSetStart, cSet);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `parseInclude` of class `MotionScene` requires synthetic accessor"
- errorLine1=" int id = motionScene.parseInclude(context, mConstraintSetStart);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIsAbstract` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition == null && !transition.mIsAbstract) {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.setRTL(mRtl);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mIsAbstract` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mIsAbstract) { // global transition only one for now"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mConstraintSetEnd == UNSET) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" transition.mTouchResponse ="
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mKeyFramesList` of class `Transition` requires synthetic accessor"
- errorLine1=" transition.mKeyFramesList.add(keyFrames);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mKeyFramesList` of class `Transition` requires synthetic accessor"
- errorLine1=" for (KeyFrames keyFrames : mDefaultTransition.mKeyFramesList) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mKeyFramesList` of class `Transition` requires synthetic accessor"
- errorLine1=" for (KeyFrames keyFrames : mCurrentTransition.mKeyFramesList) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mKeyFramesList` of class `Transition` requires synthetic accessor"
- errorLine1=" for (KeyFrames keyFrames : mCurrentTransition.mKeyFramesList) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mConstraintSetStart == stateId) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mKeyFramesList` of class `Transition` requires synthetic accessor"
- errorLine1=" for (KeyFrames keyFrames : mCurrentTransition.mKeyFramesList) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mKeyFramesList` of class `Transition` requires synthetic accessor"
- errorLine1=" for (KeyFrames keyFrames : mCurrentTransition.mKeyFramesList) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (transition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition != null && mCurrentTransition.mTouchResponse != null;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" region = mCurrentTransition.mTouchResponse"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" region = mCurrentTransition.mTouchResponse"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.setDown(mLastTouchX, mLastTouchY);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" .mTouchResponse.getTouchRegion(mMotionLayout, cache);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.setUpTouchEvent(mLastTouchX, mLastTouchY);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.processTouchEvent(event,"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.scrollMove(dx, dy);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.scrollUp(dx, dy);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getProgressDirection(dx, dy);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetStart` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mConstraintSetStart;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConstraintSetEnd` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mConstraintSetEnd;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDefaultInterpolator` of class `Transition` requires synthetic accessor"
- errorLine1=" switch (mCurrentTransition.mDefaultInterpolator) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDefaultInterpolatorString` of class `Transition` requires synthetic accessor"
- errorLine1=" .getInterpolator(mCurrentTransition.mDefaultInterpolatorString);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDefaultInterpolatorID` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mDefaultInterpolatorID);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mDuration` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mDuration;"
- errorLine2=" ~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mPathMotionArc` of class `Transition` requires synthetic accessor"
- errorLine1=" return (mCurrentTransition != null) ? mCurrentTransition.mPathMotionArc : UNSET;"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mStagger` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mStagger;"
- errorLine2=" ~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getMaxAcceleration();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getMaxVelocity();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getSpringStiffness();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getSpringMass();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getSpringDamping();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getSpringStopThreshold();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getSpringBoundary();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getAutoCompleteMode();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" mCurrentTransition.mTouchResponse.setupTouch();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" if (mCurrentTransition != null && mCurrentTransition.mTouchResponse != null) {"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mTouchResponse` of class `Transition` requires synthetic accessor"
- errorLine1=" return mCurrentTransition.mTouchResponse.getMoveWhenScrollAtTop();"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/MotionScene.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" int count = mMotionLayout.getChildCount();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" View view = mMotionLayout.getChildAt(i);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" int currentId = mMotionLayout.getCurrentState();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" mMotionLayout.getConstraintSet(currentId);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" ViewTransitionController.this, mMotionLayout,"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" int count = mMotionLayout.getChildCount();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" View view = mMotionLayout.getChildAt(i);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" int currentId = mMotionLayout.getCurrentState();"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" mMotionLayout.getConstraintSet(currentId);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mMotionLayout` of class `ViewTransitionController` requires synthetic accessor"
- errorLine1=" ViewTransitionController.this, mMotionLayout,"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/constraintlayout/motion/widget/ViewTransitionController.java"/>
- </issue>
-
- <issue
id="KotlinPropertyAccess"
message="The getter return type (`String[]`) and setter parameter type (`String`) getter and setter methods for property `stateLabels` should have exactly the same type to allow be accessed as a property from Kotlin; see https://android.github.io/kotlin-guides/interop.html#property-prefixes"
errorLine1=" public String[] getStateLabels() {"
diff --git a/core/core-performance-play-services/OWNERS b/core/core-performance-play-services/OWNERS
new file mode 100644
index 0000000..da22b63
--- /dev/null
+++ b/core/core-performance-play-services/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 461355
+essick@google.com
+nchalko@google.com
diff --git a/core/core-performance-play-services/api/current.txt b/core/core-performance-play-services/api/current.txt
index 0c72140..7e46ef7 100644
--- a/core/core-performance-play-services/api/current.txt
+++ b/core/core-performance-play-services/api/current.txt
@@ -1,29 +1,10 @@
// Signature format: 4.0
package androidx.core.performance.play.services {
- public final class PlayServicesDevicePerformanceRetriever implements androidx.core.performance.DevicePerformanceRetriever {
- ctor public PlayServicesDevicePerformanceRetriever(android.content.Context context);
- method public android.content.Context getContext();
- method public int getPerformanceClass();
- method public static int getPerformanceClass(android.content.Context context);
- property public final android.content.Context context;
- field public static final androidx.core.performance.play.services.PlayServicesDevicePerformanceRetriever.Companion Companion;
- }
-
- public static final class PlayServicesDevicePerformanceRetriever.Companion {
- method public int getPerformanceClass(android.content.Context context);
- }
-
- public final class PlayServicesDevicePerformanceSupplier implements androidx.core.performance.DevicePerformanceSupplier {
- ctor public PlayServicesDevicePerformanceSupplier();
- method public static androidx.core.performance.DevicePerformance createDevicePerformance(android.content.Context context);
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
- field public static final androidx.core.performance.play.services.PlayServicesDevicePerformanceSupplier.Companion Companion;
- }
-
- public static final class PlayServicesDevicePerformanceSupplier.Companion {
- method public androidx.core.performance.DevicePerformance createDevicePerformance(android.content.Context context);
+ public final class PlayServicesDevicePerformance implements androidx.core.performance.DevicePerformance {
+ ctor public PlayServicesDevicePerformance(android.content.Context context);
+ method public int getMediaPerformanceClass();
+ property public int mediaPerformanceClass;
}
}
diff --git a/core/core-performance-play-services/api/restricted_current.txt b/core/core-performance-play-services/api/restricted_current.txt
index 0c72140..7e46ef7 100644
--- a/core/core-performance-play-services/api/restricted_current.txt
+++ b/core/core-performance-play-services/api/restricted_current.txt
@@ -1,29 +1,10 @@
// Signature format: 4.0
package androidx.core.performance.play.services {
- public final class PlayServicesDevicePerformanceRetriever implements androidx.core.performance.DevicePerformanceRetriever {
- ctor public PlayServicesDevicePerformanceRetriever(android.content.Context context);
- method public android.content.Context getContext();
- method public int getPerformanceClass();
- method public static int getPerformanceClass(android.content.Context context);
- property public final android.content.Context context;
- field public static final androidx.core.performance.play.services.PlayServicesDevicePerformanceRetriever.Companion Companion;
- }
-
- public static final class PlayServicesDevicePerformanceRetriever.Companion {
- method public int getPerformanceClass(android.content.Context context);
- }
-
- public final class PlayServicesDevicePerformanceSupplier implements androidx.core.performance.DevicePerformanceSupplier {
- ctor public PlayServicesDevicePerformanceSupplier();
- method public static androidx.core.performance.DevicePerformance createDevicePerformance(android.content.Context context);
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
- field public static final androidx.core.performance.play.services.PlayServicesDevicePerformanceSupplier.Companion Companion;
- }
-
- public static final class PlayServicesDevicePerformanceSupplier.Companion {
- method public androidx.core.performance.DevicePerformance createDevicePerformance(android.content.Context context);
+ public final class PlayServicesDevicePerformance implements androidx.core.performance.DevicePerformance {
+ ctor public PlayServicesDevicePerformance(android.content.Context context);
+ method public int getMediaPerformanceClass();
+ property public int mediaPerformanceClass;
}
}
diff --git a/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformance.kt b/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformance.kt
new file mode 100644
index 0000000..e728cbe
--- /dev/null
+++ b/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformance.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.performance.play.services
+
+import android.content.Context
+import androidx.core.performance.DevicePerformance
+import com.google.android.gms.deviceperformance.DevicePerformanceClient
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.tasks.await
+
+/**
+ * A DevicePerformance that uses Google Play Services to retrieve media performance class data.
+ *
+ * @param context The application context value to use.
+ */
+class PlayServicesDevicePerformance(private val context: Context) : DevicePerformance {
+ // TODO(b/292643991): Add caching mechanism to play service androidx
+ override val mediaPerformanceClass: Int = getPerformanceClass(context)
+
+ private fun getPerformanceClass(context: Context): Int {
+ val client: DevicePerformanceClient =
+ com.google.android.gms.deviceperformance.DevicePerformance.getClient(context)
+ return runBlocking { client.mediaPerformanceClass().await() }
+ }
+}
diff --git a/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceRetriever.kt b/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceRetriever.kt
deleted file mode 100644
index ea1ea30..0000000
--- a/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceRetriever.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance.play.services
-
-import android.content.Context
-import androidx.core.performance.DevicePerformanceRetriever
-import com.google.android.gms.deviceperformance.DevicePerformanceClient
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.tasks.await
-
-/**
- * A DevicePerformanceRetriever that uses Google Play Services to retrieve media performance class data.
- *
- * @param context The application context value to use.
- */
-class PlayServicesDevicePerformanceRetriever(val context: Context) : DevicePerformanceRetriever {
- override fun getPerformanceClass(): Int =
- PlayServicesDevicePerformanceRetriever.getPerformanceClass(
- context
- );
-
- companion object {
- @JvmStatic
- fun getPerformanceClass(context: Context): Int {
- val client: DevicePerformanceClient =
- com.google.android.gms.deviceperformance.DevicePerformance.getClient(context)
- return runBlocking { client.mediaPerformanceClass().await() }
- }
- }
-}
diff --git a/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceSupplier.kt b/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceSupplier.kt
deleted file mode 100644
index a7a2792..0000000
--- a/core/core-performance-play-services/src/main/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceSupplier.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance.play.services
-
-import android.content.Context
-import androidx.core.performance.DevicePerformance
-import androidx.core.performance.DevicePerformanceSupplier
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-
-/** Uses Google Play Services to supply media performance class data. */
-class PlayServicesDevicePerformanceSupplier : DevicePerformanceSupplier {
-
- companion object {
- /**
- * Create DevicePerformance from the context backed by StaticDevicePerformanceSupplier.
- *
- * This should be done in [android.app.Application.onCreate].
- */
- @JvmStatic
- fun createDevicePerformance(
- // Real implementations will require a context
- @Suppress("UNUSED_PARAMETER") context: Context
- ): DevicePerformance =
- DevicePerformance.create(PlayServicesDevicePerformanceSupplier())
- }
-
- override val mediaPerformanceClassFlow: Flow<Int> = flow {
- emit(0)
- // TODO(281079628): implement
- }
-}
diff --git a/core/core-performance-play-services/src/test/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceSupplierTest.kt b/core/core-performance-play-services/src/test/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceSupplierTest.kt
deleted file mode 100644
index 4646c9c..0000000
--- a/core/core-performance-play-services/src/test/java/androidx/core/performance/play/services/PlayServicesDevicePerformanceSupplierTest.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance.play.services
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [PlayServicesDevicePerformanceSupplier]. */
-class PlayServicesDevicePerformanceSupplierTest {
-
- @Test
- fun mediaPerformanceClassFlow_30() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
diff --git a/core/core-performance-testing/api/current.txt b/core/core-performance-testing/api/current.txt
index 73eaa82..6e565c7 100644
--- a/core/core-performance-testing/api/current.txt
+++ b/core/core-performance-testing/api/current.txt
@@ -1,17 +1,10 @@
// Signature format: 4.0
package androidx.core.performance.testing {
- public final class FakeDevicePerformanceRetriever implements androidx.core.performance.DevicePerformanceRetriever {
- ctor public FakeDevicePerformanceRetriever(int mediaPerformanceClass);
+ public final class FakeDevicePerformance implements androidx.core.performance.DevicePerformance {
+ ctor public FakeDevicePerformance(int mediaPerformanceClass);
method public int getMediaPerformanceClass();
- method public int getPerformanceClass();
- property public final int mediaPerformanceClass;
- }
-
- public final class FakeDevicePerformanceSupplier implements androidx.core.performance.DevicePerformanceSupplier {
- ctor public FakeDevicePerformanceSupplier(int mediaPerformanceClass);
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
+ property public int mediaPerformanceClass;
}
}
diff --git a/core/core-performance-testing/api/restricted_current.txt b/core/core-performance-testing/api/restricted_current.txt
index 73eaa82..6e565c7 100644
--- a/core/core-performance-testing/api/restricted_current.txt
+++ b/core/core-performance-testing/api/restricted_current.txt
@@ -1,17 +1,10 @@
// Signature format: 4.0
package androidx.core.performance.testing {
- public final class FakeDevicePerformanceRetriever implements androidx.core.performance.DevicePerformanceRetriever {
- ctor public FakeDevicePerformanceRetriever(int mediaPerformanceClass);
+ public final class FakeDevicePerformance implements androidx.core.performance.DevicePerformance {
+ ctor public FakeDevicePerformance(int mediaPerformanceClass);
method public int getMediaPerformanceClass();
- method public int getPerformanceClass();
- property public final int mediaPerformanceClass;
- }
-
- public final class FakeDevicePerformanceSupplier implements androidx.core.performance.DevicePerformanceSupplier {
- ctor public FakeDevicePerformanceSupplier(int mediaPerformanceClass);
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
+ property public int mediaPerformanceClass;
}
}
diff --git a/core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformanceRetriever.kt b/core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformance.kt
similarity index 70%
rename from core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformanceRetriever.kt
rename to core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformance.kt
index 284a229..c522f31 100644
--- a/core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformanceRetriever.kt
+++ b/core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformance.kt
@@ -16,13 +16,11 @@
package androidx.core.performance.testing
-import androidx.core.performance.DevicePerformanceRetriever
+import androidx.core.performance.DevicePerformance
/**
- * A DevicePerformanceRetriever that immediately returns the `mediaPerformanceClass`.
+ * A DevicePerformance that immediately returns the `mediaPerformanceClass`.
*
* @param mediaPerformanceClass The media performance class value to return.
*/
-class FakeDevicePerformanceRetriever(val mediaPerformanceClass: Int) : DevicePerformanceRetriever {
- override fun getPerformanceClass(): Int = mediaPerformanceClass
-}
+class FakeDevicePerformance(override val mediaPerformanceClass: Int) : DevicePerformance
diff --git a/core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformanceSupplier.kt b/core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformanceSupplier.kt
deleted file mode 100644
index 3a02368..0000000
--- a/core/core-performance-testing/src/main/java/androidx/core/performance/testing/FakeDevicePerformanceSupplier.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance.testing
-
-import androidx.core.performance.DevicePerformanceSupplier
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-
-/**
- * A DevicePerformanceSupplier that immediately emits the `mediaPerformanceClass` provided and
- * completes the flow.
- *
- * @param mediaPerformanceClass The media performance class value to emit.
- */
-class FakeDevicePerformanceSupplier(private val mediaPerformanceClass: Int) :
- DevicePerformanceSupplier {
- override val mediaPerformanceClassFlow: Flow<Int> = flow {
- emit(mediaPerformanceClass)
- }
-}
diff --git a/core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceSupplierTest.kt b/core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceSupplierTest.kt
deleted file mode 100644
index 76787d6..0000000
--- a/core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceSupplierTest.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance.testing
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [FakeDevicePerformanceSupplier]. */
-class FakeDevicePerformanceSupplierTest {
-
- @Test
- fun mediaPerformanceClassFlow_30() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
diff --git a/core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceRetrieverTest.kt b/core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceTest.kt
similarity index 79%
rename from core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceRetrieverTest.kt
rename to core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceTest.kt
index b45d2d7..8153a0b3 100644
--- a/core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceRetrieverTest.kt
+++ b/core/core-performance-testing/src/test/java/androidx/core/performance/testing/FakeDevicePerformanceTest.kt
@@ -19,13 +19,12 @@
import com.google.common.truth.Truth.assertThat
import org.junit.Test
-/** Unit test for [FakeDevicePerformanceRetriever]. */
-class FakeDevicePerformanceRetrieverTest {
+/** Unit test for [FakeDevicePerformance]. */
+class FakeDevicePerformanceTest {
@Test
fun mediaPerformanceClass_30() {
- val retriever = FakeDevicePerformanceRetriever(30)
- val mpc = retriever.getPerformanceClass()
+ val mpc = FakeDevicePerformance(30).mediaPerformanceClass
assertThat(mpc).isEqualTo(30)
}
}
diff --git a/core/core-performance/api/current.txt b/core/core-performance/api/current.txt
index c85cbcb..05ff76d2 100644
--- a/core/core-performance/api/current.txt
+++ b/core/core-performance/api/current.txt
@@ -1,50 +1,15 @@
// Signature format: 4.0
package androidx.core.performance {
- public final class DefaultDevicePerformanceRetriever implements androidx.core.performance.DevicePerformanceRetriever {
- ctor public DefaultDevicePerformanceRetriever();
- method public int getPerformanceClass();
+ public final class DefaultDevicePerformance implements androidx.core.performance.DevicePerformance {
+ ctor public DefaultDevicePerformance();
+ method public int getMediaPerformanceClass();
+ property public int mediaPerformanceClass;
}
@kotlin.jvm.JvmDefaultWithCompatibility public interface DevicePerformance {
- method public static androidx.core.performance.DevicePerformance create(androidx.core.performance.DevicePerformanceSupplier devicePerformanceSupplier);
method public int getMediaPerformanceClass();
property public abstract int mediaPerformanceClass;
- field public static final androidx.core.performance.DevicePerformance.Companion Companion;
- }
-
- public static final class DevicePerformance.Companion {
- method public androidx.core.performance.DevicePerformance create(androidx.core.performance.DevicePerformanceSupplier devicePerformanceSupplier);
- }
-
- public interface DevicePerformanceRetriever {
- method public int getPerformanceClass();
- }
-
- public interface DevicePerformanceSupplier {
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public abstract kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
- }
-
- public interface MediaPerformance {
- method public static int getPerformanceClass(optional androidx.core.performance.DevicePerformanceRetriever retriever);
- field public static final androidx.core.performance.MediaPerformance.Companion Companion;
- }
-
- public static final class MediaPerformance.Companion {
- method public int getPerformanceClass(optional androidx.core.performance.DevicePerformanceRetriever retriever);
- }
-
- public final class StaticDevicePerformanceSupplier implements androidx.core.performance.DevicePerformanceSupplier {
- ctor public StaticDevicePerformanceSupplier();
- method public static androidx.core.performance.DevicePerformance createDevicePerformance();
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
- field public static final androidx.core.performance.StaticDevicePerformanceSupplier.Companion Companion;
- }
-
- public static final class StaticDevicePerformanceSupplier.Companion {
- method public androidx.core.performance.DevicePerformance createDevicePerformance();
}
}
diff --git a/core/core-performance/api/restricted_current.txt b/core/core-performance/api/restricted_current.txt
index c85cbcb..05ff76d2 100644
--- a/core/core-performance/api/restricted_current.txt
+++ b/core/core-performance/api/restricted_current.txt
@@ -1,50 +1,15 @@
// Signature format: 4.0
package androidx.core.performance {
- public final class DefaultDevicePerformanceRetriever implements androidx.core.performance.DevicePerformanceRetriever {
- ctor public DefaultDevicePerformanceRetriever();
- method public int getPerformanceClass();
+ public final class DefaultDevicePerformance implements androidx.core.performance.DevicePerformance {
+ ctor public DefaultDevicePerformance();
+ method public int getMediaPerformanceClass();
+ property public int mediaPerformanceClass;
}
@kotlin.jvm.JvmDefaultWithCompatibility public interface DevicePerformance {
- method public static androidx.core.performance.DevicePerformance create(androidx.core.performance.DevicePerformanceSupplier devicePerformanceSupplier);
method public int getMediaPerformanceClass();
property public abstract int mediaPerformanceClass;
- field public static final androidx.core.performance.DevicePerformance.Companion Companion;
- }
-
- public static final class DevicePerformance.Companion {
- method public androidx.core.performance.DevicePerformance create(androidx.core.performance.DevicePerformanceSupplier devicePerformanceSupplier);
- }
-
- public interface DevicePerformanceRetriever {
- method public int getPerformanceClass();
- }
-
- public interface DevicePerformanceSupplier {
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public abstract kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
- }
-
- public interface MediaPerformance {
- method public static int getPerformanceClass(optional androidx.core.performance.DevicePerformanceRetriever retriever);
- field public static final androidx.core.performance.MediaPerformance.Companion Companion;
- }
-
- public static final class MediaPerformance.Companion {
- method public int getPerformanceClass(optional androidx.core.performance.DevicePerformanceRetriever retriever);
- }
-
- public final class StaticDevicePerformanceSupplier implements androidx.core.performance.DevicePerformanceSupplier {
- ctor public StaticDevicePerformanceSupplier();
- method public static androidx.core.performance.DevicePerformance createDevicePerformance();
- method public kotlinx.coroutines.flow.Flow<java.lang.Integer> getMediaPerformanceClassFlow();
- property public kotlinx.coroutines.flow.Flow<java.lang.Integer> mediaPerformanceClassFlow;
- field public static final androidx.core.performance.StaticDevicePerformanceSupplier.Companion Companion;
- }
-
- public static final class StaticDevicePerformanceSupplier.Companion {
- method public androidx.core.performance.DevicePerformance createDevicePerformance();
}
}
diff --git a/core/core-performance/integration-tests/testapp/build.gradle b/core/core-performance/integration-tests/testapp/build.gradle
new file mode 100644
index 0000000..2925db8
--- /dev/null
+++ b/core/core-performance/integration-tests/testapp/build.gradle
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+ id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+ api(libs.kotlinStdlib)
+ implementation(project(":core:core-performance"))
+ implementation libs.constraintLayout
+}
+
+android {
+ defaultConfig {
+ applicationId "androidx.core.performance.testapp"
+ minSdkVersion 24
+ }
+
+ namespace "androidx.core.performance.testapp"
+}
\ No newline at end of file
diff --git a/core/core-performance/integration-tests/testapp/src/main/AndroidManifest.xml b/core/core-performance/integration-tests/testapp/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e4235b71e
--- /dev/null
+++ b/core/core-performance/integration-tests/testapp/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <application>
+ <activity
+ android:name=".MpcActivity"
+
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/core/core-performance/integration-tests/testapp/src/main/java/androidx/core/performance/testapp/MpcActivity.kt b/core/core-performance/integration-tests/testapp/src/main/java/androidx/core/performance/testapp/MpcActivity.kt
new file mode 100644
index 0000000..b4c68ab
--- /dev/null
+++ b/core/core-performance/integration-tests/testapp/src/main/java/androidx/core/performance/testapp/MpcActivity.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.performance.testapp
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.View
+import android.widget.TextView
+
+/** Sample Media Performance Class activity. */
+class MpcActivity : Activity() {
+
+ private lateinit var resultTextView: TextView
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_mpc)
+ resultTextView = findViewById(R.id.resultTextView)
+ }
+
+ fun doSomething(view: View) {
+ resultTextView.text = view.context.getString(getExperienceStringId())
+ }
+
+ private fun getExperienceStringId(): Int {
+ return R.string.mpc_0_experience_string
+ }
+}
diff --git a/core/core-performance/integration-tests/testapp/src/main/res/layout/activity_mpc.xml b/core/core-performance/integration-tests/testapp/src/main/res/layout/activity_mpc.xml
new file mode 100644
index 0000000..7a2010c
--- /dev/null
+++ b/core/core-performance/integration-tests/testapp/src/main/res/layout/activity_mpc.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MpcActivity">
+
+ <Button
+ android:id="@+id/doSomething"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="8dp"
+ android:layout_marginTop="16dp"
+ android:onClick="doSomething"
+ android:text="Do something"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <TextView
+ android:id="@+id/resultTextView"
+
+ android:layout_width="0dp"
+ android:layout_height="87dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginTop="8dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="@+id/doSomething"
+ app:layout_constraintTop_toBottomOf="@+id/doSomething" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/core/core-performance/integration-tests/testapp/src/main/res/values/strings.xml b/core/core-performance/integration-tests/testapp/src/main/res/values/strings.xml
new file mode 100644
index 0000000..4c2d1b7
--- /dev/null
+++ b/core/core-performance/integration-tests/testapp/src/main/res/values/strings.xml
@@ -0,0 +1,23 @@
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string name="mpc_0_experience_string">Default and simple experience.</string>
+ <string name="mpc_29_experience_string">Media Performance Class 10 experience.</string>
+ <string name="mpc_30_experience_string">Media Performance Class 11 experience.</string>
+ <string name="mpc_31_experience_string">Media Performance Class 12 experience.</string>
+ <string name="mpc_33_experience_string">Media Performance Class 13 experience.</string>
+</resources>
\ No newline at end of file
diff --git a/core/core-performance/samples/build.gradle b/core/core-performance/samples/build.gradle
index 0087990..ef28e3c 100644
--- a/core/core-performance/samples/build.gradle
+++ b/core/core-performance/samples/build.gradle
@@ -30,7 +30,7 @@
}
androidx {
- name = "cSamples"
+ name = "Core Performance Samples"
type = LibraryType.SAMPLES
mavenVersion = LibraryVersions.CORE_PERFORMANCE
inceptionYear = "2021"
diff --git a/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt b/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt
index 60f10f0..5f5be1c 100644
--- a/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt
+++ b/core/core-performance/samples/src/main/java/androidx/core/performance/samples/Usage.kt
@@ -19,8 +19,8 @@
import android.app.Application
import android.os.Build
import androidx.annotation.Sampled
+import androidx.core.performance.DefaultDevicePerformance
import androidx.core.performance.DevicePerformance
-import androidx.core.performance.play.services.PlayServicesDevicePerformanceSupplier
@Sampled
fun usage() {
@@ -30,13 +30,13 @@
private lateinit var devicePerformance: DevicePerformance
override fun onCreate() {
- devicePerformance =
- PlayServicesDevicePerformanceSupplier.createDevicePerformance(applicationContext)
+ // use a DevicePerformance derived class
+ devicePerformance = DefaultDevicePerformance()
}
fun doSomeThing() {
when {
- devicePerformance.mediaPerformanceClass >= Build.VERSION_CODES.S -> {
+ devicePerformance.mediaPerformanceClass >= Build.VERSION_CODES.TIRAMISU -> {
// Provide the most premium experience for highest performing devices
}
devicePerformance.mediaPerformanceClass == Build.VERSION_CODES.R -> {
diff --git a/core/core-performance/src/main/java/androidx/core/performance/DefaultDevicePerformance.kt b/core/core-performance/src/main/java/androidx/core/performance/DefaultDevicePerformance.kt
new file mode 100644
index 0000000..3917fad
--- /dev/null
+++ b/core/core-performance/src/main/java/androidx/core/performance/DefaultDevicePerformance.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.performance
+
+import android.os.Build
+
+/**
+ * Reports the media performance class of the device. Contains statically specified values
+ * and can be used as a fallback alternative to suppliers with dynamic values.
+ */
+class DefaultDevicePerformance() : DevicePerformance {
+ private val PERFCLASS_11: Int = Build.VERSION_CODES.R
+ private val PERFCLASS_12: Int = Build.VERSION_CODES.S
+ private val PERFCLASS_13: Int = Build.VERSION_CODES.TIRAMISU
+ private val PERFCLASS_NONE: Int = 0
+
+ private val fingerprints: HashMap<String, Int> = hashMapOf(
+ // for unit testing, no actual products with these
+ "robolectric-BrandX/ProductX/Device30:11" to PERFCLASS_11,
+ "robolectric-BrandX/ProductX/Device31:12" to PERFCLASS_12,
+
+ // actual devices in the field
+ "OPPO/CPH2025EEA/OP4BA2L1:12" to PERFCLASS_11,
+ "OPPO/CPH2207EEA/OP4F0BL1:12" to PERFCLASS_11,
+ "OPPO/PENM00/OP4EC1:11" to PERFCLASS_11,
+ "OnePlus/OnePlus7TTMO/OnePlus7TTMO:11" to PERFCLASS_11,
+ "OnePlus/OnePlus8_BETA/OnePlus8:11" to PERFCLASS_11,
+ "Xiaomi/umi_global/umi:11" to PERFCLASS_11,
+ "realme/RMX2085/RMX2085L1:11" to PERFCLASS_11,
+ "samsung/c1qsqw/c1q:12" to PERFCLASS_11,
+ "samsung/o1quew/o1q:12" to PERFCLASS_11,
+ "samsung/r0quew/r0q:12" to PERFCLASS_11,
+ "samsung/r0sxxx/r0s:12" to PERFCLASS_11,
+ )
+
+ override val mediaPerformanceClass = getCalculatedMediaPerformanceClass()
+
+ private fun getMediaPerformanceClassFromFingerprint(): Int {
+
+ val brand = Build.BRAND
+ val product = Build.PRODUCT
+ val device = Build.DEVICE
+ val release = Build.VERSION.RELEASE
+
+ val synthesized = "$brand/$product/$device:$release"
+ var pc = fingerprints[synthesized]
+
+ if (pc == null) {
+ pc = PERFCLASS_NONE
+ }
+ return pc
+ }
+
+ private fun getMediaPerformanceClassFromProperty(): Int {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ return Build.VERSION.MEDIA_PERFORMANCE_CLASS
+ }
+
+ return PERFCLASS_NONE
+ }
+
+ private fun isPerformanceClassValid(pc: Int): Boolean = pc >= PERFCLASS_11
+
+ private fun getCalculatedMediaPerformanceClass(): Int {
+
+ // device's declared property takes precedence over our in-library table.
+ val mpcViaProperty: Int =
+ getMediaPerformanceClassFromProperty()
+
+ if (isPerformanceClassValid(mpcViaProperty)) {
+ return mpcViaProperty
+ }
+
+ val mpcViaFingerprint: Int =
+ getMediaPerformanceClassFromFingerprint()
+
+ if (isPerformanceClassValid(mpcViaFingerprint)) {
+ return mpcViaFingerprint
+ }
+
+ return PERFCLASS_NONE
+ }
+}
diff --git a/core/core-performance/src/main/java/androidx/core/performance/DevicePerformance.kt b/core/core-performance/src/main/java/androidx/core/performance/DevicePerformance.kt
index 02502a0..8b187f1 100644
--- a/core/core-performance/src/main/java/androidx/core/performance/DevicePerformance.kt
+++ b/core/core-performance/src/main/java/androidx/core/performance/DevicePerformance.kt
@@ -16,10 +16,6 @@
package androidx.core.performance
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.last
-import kotlinx.coroutines.runBlocking
-
@JvmDefaultWithCompatibility
/**
* Reports the media performance class of the device.
@@ -47,44 +43,4 @@
*
*/
val mediaPerformanceClass: Int
-
- companion object {
- /**
- * Create PerformanceClass from the context.
- *
- * This should be done in [android.app.Application.onCreate].
- *
- * Developers should call the createDevicePerformance companion method of
- * the desired DevicePerformanceSupplier implementation.
- *
- * @param devicePerformanceSupplier Supplies device performance.
- */
- @JvmStatic
- fun create(
- devicePerformanceSupplier: DevicePerformanceSupplier
- ): DevicePerformance = DefaultDevicePerformanceImpl(devicePerformanceSupplier)
- }
-}
-
-/**
- * Supplies a flow of mediaPerformanceClass
- */
-interface DevicePerformanceSupplier {
-
- val mediaPerformanceClassFlow: Flow<Int>
-}
-
-/**
- * Lazy caches the mediaPerformanceClass
- */
-private class DefaultDevicePerformanceImpl(
- val devicePerformanceSupplier: DevicePerformanceSupplier
-) : DevicePerformance {
- private val logTag = "DefaultDevicePerformanceImpl"
-
- override val mediaPerformanceClass by lazy(mode = LazyThreadSafetyMode.PUBLICATION) {
- runBlocking {
- devicePerformanceSupplier.mediaPerformanceClassFlow.last()
- }
- }
}
diff --git a/core/core-performance/src/main/java/androidx/core/performance/MediaPerformance.kt b/core/core-performance/src/main/java/androidx/core/performance/MediaPerformance.kt
deleted file mode 100644
index 35282c9..0000000
--- a/core/core-performance/src/main/java/androidx/core/performance/MediaPerformance.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance
-
-/**
- * Interface implemented by all device performance retrievers.
- */
-interface DevicePerformanceRetriever {
- fun getPerformanceClass(): Int
-}
-
-/**
- * Default implementation for a device performance retriever.
- */
-class DefaultDevicePerformanceRetriever : DevicePerformanceRetriever {
- override fun getPerformanceClass(): Int = 0
-}
-
-/**
- * Main interface used to get the performance class using a specific retriever.
- */
-interface MediaPerformance {
- companion object {
- @JvmStatic
- fun getPerformanceClass(
- retriever: DevicePerformanceRetriever =
- DefaultDevicePerformanceRetriever()
- ): Int = retriever.getPerformanceClass()
- }
-}
diff --git a/core/core-performance/src/main/java/androidx/core/performance/StaticDevicePerformanceSupplier.kt b/core/core-performance/src/main/java/androidx/core/performance/StaticDevicePerformanceSupplier.kt
deleted file mode 100644
index 5c31e45..0000000
--- a/core/core-performance/src/main/java/androidx/core/performance/StaticDevicePerformanceSupplier.kt
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance
-
-import android.os.Build
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
-
-/**
- * Reports the media performance class of the device. Contains statically specified values
- * and can be used as a fallback alternative to suppliers with dynamic values.
- */
-class StaticDevicePerformanceSupplier : DevicePerformanceSupplier {
-
- companion object {
- /**
- * Create DevicePerformance from the context backed by StaticDevicePerformanceSupplier.
- *
- * This should be done in [android.app.Application.onCreate].
- */
- @JvmStatic
- fun createDevicePerformance(): DevicePerformance =
- DevicePerformance.create(StaticDevicePerformanceSupplier())
- }
-
- override val mediaPerformanceClassFlow: Flow<Int> = flow {
- emit(calculateMediaPerformanceClass())
- }
-
- // the next code isn't published/finalized until late
- private val PERFCLASS_11: Int = Build.VERSION_CODES.R
- private val PERFCLASS_12: Int = Build.VERSION_CODES.S
- private val PERFCLASS_13: Int = 33
-
- // we synthesize our own fingerprint:
- // Brand/Product/Device:api
- // this is currently the prefix in the actual build fingerprints,
- // so it is easy to cut&paste info from there into this list.
- //
- private val fingerprints: HashMap<String, Int> = hashMapOf(
- // for unit testing, no actual products with these
- "robolectric-BrandX/ProductX/Device30:11" to PERFCLASS_11,
- "robolectric-BrandX/ProductX/Device31:12" to PERFCLASS_12,
-
- // actual devices in the field
- "OPPO/CPH2025EEA/OP4BA2L1:12" to PERFCLASS_11,
- "OPPO/CPH2207EEA/OP4F0BL1:12" to PERFCLASS_11,
- "OPPO/PENM00/OP4EC1:11" to PERFCLASS_11,
- "OnePlus/OnePlus7TTMO/OnePlus7TTMO:11" to PERFCLASS_11,
- "OnePlus/OnePlus8_BETA/OnePlus8:11" to PERFCLASS_11,
- "Xiaomi/umi_global/umi:11" to PERFCLASS_11,
- "realme/RMX2085/RMX2085L1:11" to PERFCLASS_11,
- "samsung/c1qsqw/c1q:12" to PERFCLASS_11,
- "samsung/o1quew/o1q:12" to PERFCLASS_11,
- "samsung/r0quew/r0q:12" to PERFCLASS_11,
- "samsung/r0sxxx/r0s:12" to PERFCLASS_11,
- )
-
- private fun calculateMediaPerformanceClassFromFingerprint(): Int {
-
- val brand = Build.BRAND
- val product = Build.PRODUCT
- val device = Build.DEVICE
- val release = Build.VERSION.RELEASE
-
- val synthesized = "$brand/$product/$device:$release"
- var pc = fingerprints[synthesized]
-
- if (pc == null) {
- pc = 0
- }
- return pc
- }
-
- private fun calculateMediaPerformanceClassFromProperty(): Int {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- return Build.VERSION.MEDIA_PERFORMANCE_CLASS
- }
- return 0
- }
-
- // discard illegal performance class numbers
- private fun boundPC(pc: Int): Int {
- if (pc < PERFCLASS_11) {
- // performance class 11 is the first legal value for performance class
- return 0
- }
- return pc
- }
-
- private fun calculateMediaPerformanceClass(): Int {
-
- // device's declared property takes precedence over our in-library table.
- //
- // what this flow doesn't let us express is a device with property PC11
- // to actually upgraded to PC12 via the table.
- //
- val viaProperty: Int = boundPC(calculateMediaPerformanceClassFromProperty())
- if (viaProperty > 0) {
- return viaProperty
- }
- val viaFingerprint: Int = calculateMediaPerformanceClassFromFingerprint()
- return boundPC(viaFingerprint)
- }
-}
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DefaultDevicePerformanceTest.kt b/core/core-performance/src/test/java/androidx/core/performance/DefaultDevicePerformanceTest.kt
new file mode 100644
index 0000000..5a5b514
--- /dev/null
+++ b/core/core-performance/src/test/java/androidx/core/performance/DefaultDevicePerformanceTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.performance
+
+import android.os.Build.VERSION_CODES.R
+import android.os.Build.VERSION_CODES.S
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.shadows.ShadowBuild
+import org.robolectric.shadows.ShadowSystemProperties
+
+/** Unit tests for [DefaultDevicePerformance]. */
+@RunWith(RobolectricTestRunner::class)
+class DefaultDevicePerformanceTest {
+
+ @Test
+ @Config(maxSdk = R, minSdk = R)
+ fun mediaPerformanceClass_SdkR_DeclaredMpc() = runTest {
+ ShadowSystemProperties.override("ro.odm.build.media_performance_class", "30")
+ ShadowBuild.reset()
+ val mpc = DefaultDevicePerformance().mediaPerformanceClass
+ assertThat(mpc).isEqualTo(0)
+ }
+
+ @Test
+ @Config(minSdk = S)
+ fun mediaPerformanceClass_SdkS_DeclaredMpc() = runTest {
+ ShadowSystemProperties.override("ro.odm.build.media_performance_class", "30")
+ ShadowBuild.reset()
+ val mpc = DefaultDevicePerformance().mediaPerformanceClass
+ assertThat(mpc).isEqualTo(30)
+ }
+
+ @Test
+ @Config(minSdk = S)
+ fun mediaPerformanceClass_SdkS_BuildFingerprintMatch() = runTest {
+ ShadowBuild.reset()
+ ShadowBuild.setBrand("robolectric-BrandX")
+ ShadowBuild.setProduct("ProductX")
+ ShadowBuild.setDevice("Device31")
+ ShadowBuild.setVersionRelease("12")
+ val mpc = DefaultDevicePerformance().mediaPerformanceClass
+ assertThat(mpc).isEqualTo(31)
+ }
+
+ @Test
+ @Config(minSdk = S)
+ fun mediaPerformanceClass_SdkS_DeclaredMpc_BuildFingerprintMatch() = runTest {
+ ShadowSystemProperties.override("ro.odm.build.media_performance_class", "30")
+ ShadowBuild.reset()
+ ShadowBuild.setBrand("robolectric-BrandX")
+ ShadowBuild.setProduct("ProductX")
+ ShadowBuild.setDevice("Device31")
+ ShadowBuild.setVersionRelease("12")
+ val mpc = DefaultDevicePerformance().mediaPerformanceClass
+ assertThat(mpc).isEqualTo(30)
+ }
+}
diff --git a/core/core-performance/src/test/java/androidx/core/performance/MediaPerformanceTest.kt b/core/core-performance/src/test/java/androidx/core/performance/MediaPerformanceTest.kt
deleted file mode 100644
index 2f30c43..0000000
--- a/core/core-performance/src/test/java/androidx/core/performance/MediaPerformanceTest.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.core.performance
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [MediaPerformance]. */
-class MediaPerformanceTest {
-
- @Test
- fun mediaPerformanceClassWithUnspecifiedRetriever() {
- val mpc = MediaPerformance.getPerformanceClass()
- assertThat(mpc).isEqualTo(0)
- }
-
- @Test
- fun mediaPerformanceClassWithSpecifiedDefaultRetriever() {
- val mpc = MediaPerformance.getPerformanceClass(
- DefaultDevicePerformanceRetriever()
- )
- assertThat(mpc).isEqualTo(0)
- }
-}
diff --git a/core/core-performance/src/test/java/androidx/core/performance/StaticDevicePerformanceTest.kt b/core/core-performance/src/test/java/androidx/core/performance/StaticDevicePerformanceTest.kt
deleted file mode 100644
index e27e43d..0000000
--- a/core/core-performance/src/test/java/androidx/core/performance/StaticDevicePerformanceTest.kt
+++ /dev/null
@@ -1,30 +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.core.performance
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-
-/** Unit tests for [StaticDevicePerformanceSupplier]. */
-class StaticDevicePerformanceTest {
-
- @Test
- fun getMediaPerformanceClass_sdk30() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
-}
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
index f1fff4d..302eac0 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
@@ -70,7 +70,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackAnswerCall() {
setUpV2Test()
verifyAnswerCall()
@@ -84,7 +84,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackAnswerCall() {
setUpV2Test()
verifyRejectAnswerCall(Call.STATE_ACTIVE)
@@ -96,7 +96,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackHoldCall() {
setUpV2Test()
verifyRejectHoldCall()
@@ -108,7 +108,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackUnholdCall() {
setUpV2Test()
verifyRejectUnholdCall()
@@ -120,7 +120,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackDisconnectCall() {
setUpV2Test()
verifyRejectDisconnectCall(true)
@@ -132,7 +132,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackRejectCall() {
setUpV2Test()
verifyRejectDisconnectCall(false)
@@ -145,7 +145,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackDisconnectCall() {
setUpV2Test()
verifyDisconnectCall()
@@ -158,7 +158,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackHoldCall() {
setUpV2Test()
verifyHoldCall()
@@ -171,7 +171,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackUnholdCall() {
setUpV2Test()
verifyUnholdCall()
@@ -189,7 +189,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackAnswerCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyAnswerCall()
@@ -204,7 +204,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackAnswerCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyRejectAnswerCall(Call.STATE_DISCONNECTED)
@@ -217,7 +217,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackHoldCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyRejectHoldCall()
@@ -230,7 +230,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackUnholdCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyRejectUnholdCall()
@@ -243,7 +243,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackDisconnectCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyRejectDisconnectCall(true)
@@ -256,7 +256,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRejectCallControlCallbackRejectCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyRejectDisconnectCall(false)
@@ -270,7 +270,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackDisconnectCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyDisconnectCall()
@@ -284,7 +284,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackHoldCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyHoldCall()
@@ -298,7 +298,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackUnholdCall_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyUnholdCall()
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
index 5992045..8abbb88 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
@@ -81,7 +81,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicOutgoingCall() {
setUpV2Test()
runBlocking_addCallAndSetActive(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -93,7 +93,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicIncomingCall() {
setUpV2Test()
runBlocking_addCallAndSetActive(TestUtils.INCOMING_CALL_ATTRIBUTES)
@@ -105,7 +105,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testTogglingHoldOnActiveCall() {
setUpV2Test()
runBlocking_ToggleCallAsserts(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -118,7 +118,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testTogglingHoldOnActiveCall_NoHoldCapabilities() {
setUpV2Test()
assertFalse(TestUtils.OUTGOING_NO_HOLD_CAP_CALL_ATTRIBUTES
@@ -133,7 +133,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRequestEndpointChange() {
setUpV2Test()
runBlocking_RequestEndpointChangeAsserts()
@@ -146,7 +146,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testIsMuted() {
setUpV2Test()
verifyMuteStateChange()
@@ -158,7 +158,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackOperations_CallbackNotSet() {
setUpV2Test()
verifyAnswerCallFails_CallbackNotSet()
@@ -175,7 +175,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicOutgoingCall_BackwardsCompat() {
setUpBackwardsCompatTest()
runBlocking_addCallAndSetActive(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -188,7 +188,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicIncomingCall_BackwardsCompat() {
setUpBackwardsCompatTest()
runBlocking_addCallAndSetActive(TestUtils.INCOMING_CALL_ATTRIBUTES)
@@ -201,7 +201,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testTogglingHoldOnActiveCall_BackwardsCompat() {
setUpBackwardsCompatTest()
runBlocking_ToggleCallAsserts(TestUtils.OUTGOING_CALL_ATTRIBUTES)
@@ -215,7 +215,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testTogglingHoldOnActiveCall_NoHoldCapabilities_BackwardsCompat() {
setUpBackwardsCompatTest()
assertFalse(TestUtils.OUTGOING_NO_HOLD_CAP_CALL_ATTRIBUTES
@@ -231,7 +231,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testRequestEndpointChange_BackwardsCompat() {
setUpBackwardsCompatTest()
runBlocking_RequestEndpointChangeAsserts()
@@ -246,7 +246,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testIsMuted_BackwardsCompat() {
setUpBackwardsCompatTest()
verifyMuteStateChange()
@@ -259,7 +259,7 @@
*/
@SdkSuppress(minSdkVersion = VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testBasicCallControlCallbackOperations_BackwardsCompat_CallbackNotSet() {
setUpBackwardsCompatTest()
verifyAnswerCallFails_CallbackNotSet()
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
index 280fbdb..48bc53d 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
@@ -78,7 +78,7 @@
*/
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testAddCallAssertModeInCommunication() {
setUpV2Test()
runBlocking_addCall_assertAudioModeInCommunication()
@@ -95,7 +95,7 @@
*/
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@LargeTest
- @Test
+ @Test(timeout = 10000)
fun testAddCallAssertModeInCommunication_BackwardsCompat() {
setUpBackwardsCompatTest()
runBlocking_addCall_assertAudioModeInCommunication()
diff --git a/credentials/credentials-play-services-auth/api/1.2.0-beta02.txt b/credentials/credentials-play-services-auth/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/credentials/credentials-play-services-auth/api/1.2.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/credentials/credentials-play-services-auth/api/res-1.2.0-beta02.txt b/credentials/credentials-play-services-auth/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/credentials/credentials-play-services-auth/api/res-1.2.0-beta02.txt
diff --git a/credentials/credentials-play-services-auth/api/restricted_1.2.0-beta02.txt b/credentials/credentials-play-services-auth/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/credentials/credentials-play-services-auth/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
index a18deea..4032e6e 100644
--- a/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
+++ b/credentials/credentials-play-services-auth/src/main/java/androidx/credentials/playservices/controllers/CreatePublicKeyCredential/PublicKeyCredentialControllerUtility.kt
@@ -74,7 +74,7 @@
private val JSON_KEY_CLIENT_DATA = "clientDataJSON"
private val JSON_KEY_ATTESTATION_OBJ = "attestationObject"
- private val JSON_KEY_AUTH_DATA = "authenticationData"
+ private val JSON_KEY_AUTH_DATA = "authenticatorData"
private val JSON_KEY_SIGNATURE = "signature"
private val JSON_KEY_USER_HANDLE = "userHandle"
private val JSON_KEY_RESPONSE = "response"
diff --git a/credentials/credentials/api/1.2.0-beta02.txt b/credentials/credentials/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..8c9cf86
--- /dev/null
+++ b/credentials/credentials/api/1.2.0-beta02.txt
@@ -0,0 +1,902 @@
+// Signature format: 4.0
+package androidx.credentials {
+
+ public final class ClearCredentialStateRequest {
+ ctor public ClearCredentialStateRequest();
+ }
+
+ public abstract class CreateCredentialRequest {
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final android.os.Bundle getCredentialData();
+ method public final androidx.credentials.CreateCredentialRequest.DisplayInfo getDisplayInfo();
+ method public final String? getOrigin();
+ method public final boolean getPreferImmediatelyAvailableCredentials();
+ method public final String getType();
+ method public final boolean isAutoSelectAllowed();
+ method public final boolean isSystemProviderRequired();
+ property public final android.os.Bundle candidateQueryData;
+ property public final android.os.Bundle credentialData;
+ property public final androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo;
+ property public final boolean isAutoSelectAllowed;
+ property public final boolean isSystemProviderRequired;
+ property public final String? origin;
+ property public final boolean preferImmediatelyAvailableCredentials;
+ property public final String type;
+ }
+
+ public static final class CreateCredentialRequest.DisplayInfo {
+ ctor public CreateCredentialRequest.DisplayInfo(CharSequence userId);
+ ctor public CreateCredentialRequest.DisplayInfo(CharSequence userId, optional CharSequence? userDisplayName);
+ ctor public CreateCredentialRequest.DisplayInfo(CharSequence userId, CharSequence? userDisplayName, String? preferDefaultProvider);
+ method public CharSequence? getUserDisplayName();
+ method public CharSequence getUserId();
+ property public final CharSequence? userDisplayName;
+ property public final CharSequence userId;
+ }
+
+ public abstract class CreateCredentialResponse {
+ method public final android.os.Bundle getData();
+ method public final String getType();
+ property public final android.os.Bundle data;
+ property public final String type;
+ }
+
+ public class CreateCustomCredentialRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo);
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo, optional boolean isAutoSelectAllowed);
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo, optional boolean isAutoSelectAllowed, optional String? origin);
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo, optional boolean isAutoSelectAllowed, optional String? origin, optional boolean preferImmediatelyAvailableCredentials);
+ }
+
+ public class CreateCustomCredentialResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreateCustomCredentialResponse(String type, android.os.Bundle data);
+ }
+
+ public final class CreatePasswordRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreatePasswordRequest(String id, String password);
+ ctor public CreatePasswordRequest(String id, String password, optional String? origin);
+ ctor public CreatePasswordRequest(String id, String password, optional String? origin, optional boolean preferImmediatelyAvailableCredentials);
+ ctor public CreatePasswordRequest(String id, String password, optional String? origin, optional boolean preferImmediatelyAvailableCredentials, optional boolean isAutoSelectAllowed);
+ ctor public CreatePasswordRequest(String id, String password, String? origin, String? preferDefaultProvider, boolean preferImmediatelyAvailableCredentials, boolean isAutoSelectAllowed);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+ public final class CreatePasswordResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreatePasswordResponse();
+ }
+
+ public final class CreatePublicKeyCredentialRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreatePublicKeyCredentialRequest(String requestJson);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash, optional boolean preferImmediatelyAvailableCredentials);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash, optional boolean preferImmediatelyAvailableCredentials, optional String? origin);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash, optional boolean preferImmediatelyAvailableCredentials, optional String? origin, optional boolean isAutoSelectAllowed);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, byte[]? clientDataHash, boolean preferImmediatelyAvailableCredentials, String? origin, String? preferDefaultProvider, boolean isAutoSelectAllowed);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public final class CreatePublicKeyCredentialResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreatePublicKeyCredentialResponse(String registrationResponseJson);
+ method public String getRegistrationResponseJson();
+ property public final String registrationResponseJson;
+ }
+
+ public abstract class Credential {
+ method public final android.os.Bundle getData();
+ method public final String getType();
+ property public final android.os.Bundle data;
+ property public final String type;
+ }
+
+ @RequiresApi(16) public interface CredentialManager {
+ method public default suspend Object? clearCredentialState(androidx.credentials.ClearCredentialStateRequest request, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public void clearCredentialStateAsync(androidx.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ method public static androidx.credentials.CredentialManager create(android.content.Context context);
+ method public default suspend Object? createCredential(android.content.Context context, androidx.credentials.CreateCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.CreateCredentialResponse>);
+ method public void createCredentialAsync(android.content.Context context, androidx.credentials.CreateCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.CreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method @RequiresApi(34) public android.app.PendingIntent createSettingsPendingIntent();
+ method public default suspend Object? getCredential(android.content.Context context, androidx.credentials.GetCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.GetCredentialResponse>);
+ method @RequiresApi(34) public default suspend Object? getCredential(android.content.Context context, androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle pendingGetCredentialHandle, kotlin.coroutines.Continuation<? super androidx.credentials.GetCredentialResponse>);
+ method public void getCredentialAsync(android.content.Context context, androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public void getCredentialAsync(android.content.Context context, androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle pendingGetCredentialHandle, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public default suspend Object? prepareGetCredential(androidx.credentials.GetCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.PrepareGetCredentialResponse>);
+ method @RequiresApi(34) public void prepareGetCredentialAsync(androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.PrepareGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ field public static final androidx.credentials.CredentialManager.Companion Companion;
+ }
+
+ public static final class CredentialManager.Companion {
+ method public androidx.credentials.CredentialManager create(android.content.Context context);
+ }
+
+ public interface CredentialManagerCallback<R, E> {
+ method public void onError(E e);
+ method public void onResult(R result);
+ }
+
+ public abstract class CredentialOption {
+ method public final java.util.Set<android.content.ComponentName> getAllowedProviders();
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final android.os.Bundle getRequestData();
+ method public final String getType();
+ method public final boolean isAutoSelectAllowed();
+ method public final boolean isSystemProviderRequired();
+ property public final java.util.Set<android.content.ComponentName> allowedProviders;
+ property public final android.os.Bundle candidateQueryData;
+ property public final boolean isAutoSelectAllowed;
+ property public final boolean isSystemProviderRequired;
+ property public final android.os.Bundle requestData;
+ property public final String type;
+ }
+
+ public interface CredentialProvider {
+ method public boolean isAvailableOnDevice();
+ method public void onClearCredential(androidx.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ method public void onCreateCredential(android.content.Context context, androidx.credentials.CreateCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.CreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method public void onGetCredential(android.content.Context context, androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public default void onGetCredential(android.content.Context context, androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle pendingGetCredentialHandle, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public default void onPrepareCredential(androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.PrepareGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ }
+
+ public class CustomCredential extends androidx.credentials.Credential {
+ ctor public CustomCredential(String type, android.os.Bundle data);
+ }
+
+ public final class GetCredentialRequest {
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin, optional boolean preferIdentityDocUi);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin, optional boolean preferIdentityDocUi, optional android.content.ComponentName? preferUiBrandingComponentName);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin, optional boolean preferIdentityDocUi, optional android.content.ComponentName? preferUiBrandingComponentName, optional boolean preferImmediatelyAvailableCredentials);
+ method public java.util.List<androidx.credentials.CredentialOption> getCredentialOptions();
+ method public String? getOrigin();
+ method public boolean getPreferIdentityDocUi();
+ method public boolean getPreferImmediatelyAvailableCredentials();
+ method public android.content.ComponentName? getPreferUiBrandingComponentName();
+ property public final java.util.List<androidx.credentials.CredentialOption> credentialOptions;
+ property public final String? origin;
+ property public final boolean preferIdentityDocUi;
+ property public final boolean preferImmediatelyAvailableCredentials;
+ property public final android.content.ComponentName? preferUiBrandingComponentName;
+ }
+
+ public static final class GetCredentialRequest.Builder {
+ ctor public GetCredentialRequest.Builder();
+ method public androidx.credentials.GetCredentialRequest.Builder addCredentialOption(androidx.credentials.CredentialOption credentialOption);
+ method public androidx.credentials.GetCredentialRequest build();
+ method public androidx.credentials.GetCredentialRequest.Builder setCredentialOptions(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions);
+ method public androidx.credentials.GetCredentialRequest.Builder setOrigin(String origin);
+ method public androidx.credentials.GetCredentialRequest.Builder setPreferIdentityDocUi(boolean preferIdentityDocUi);
+ method public androidx.credentials.GetCredentialRequest.Builder setPreferImmediatelyAvailableCredentials(boolean preferImmediatelyAvailableCredentials);
+ method public androidx.credentials.GetCredentialRequest.Builder setPreferUiBrandingComponentName(android.content.ComponentName? component);
+ }
+
+ public final class GetCredentialResponse {
+ ctor public GetCredentialResponse(androidx.credentials.Credential credential);
+ method public androidx.credentials.Credential getCredential();
+ property public final androidx.credentials.Credential credential;
+ }
+
+ public class GetCustomCredentialOption extends androidx.credentials.CredentialOption {
+ ctor public GetCustomCredentialOption(String type, android.os.Bundle requestData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired);
+ ctor public GetCustomCredentialOption(String type, android.os.Bundle requestData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, optional boolean isAutoSelectAllowed);
+ ctor public GetCustomCredentialOption(String type, android.os.Bundle requestData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, optional boolean isAutoSelectAllowed, optional java.util.Set<android.content.ComponentName> allowedProviders);
+ }
+
+ public final class GetPasswordOption extends androidx.credentials.CredentialOption {
+ ctor public GetPasswordOption();
+ ctor public GetPasswordOption(optional java.util.Set<java.lang.String> allowedUserIds);
+ ctor public GetPasswordOption(optional java.util.Set<java.lang.String> allowedUserIds, optional boolean isAutoSelectAllowed);
+ ctor public GetPasswordOption(optional java.util.Set<java.lang.String> allowedUserIds, optional boolean isAutoSelectAllowed, optional java.util.Set<android.content.ComponentName> allowedProviders);
+ method public java.util.Set<java.lang.String> getAllowedUserIds();
+ property public final java.util.Set<java.lang.String> allowedUserIds;
+ }
+
+ public final class GetPublicKeyCredentialOption extends androidx.credentials.CredentialOption {
+ ctor public GetPublicKeyCredentialOption(String requestJson);
+ ctor public GetPublicKeyCredentialOption(String requestJson, optional byte[]? clientDataHash);
+ ctor public GetPublicKeyCredentialOption(String requestJson, optional byte[]? clientDataHash, optional java.util.Set<android.content.ComponentName> allowedProviders);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public final class PasswordCredential extends androidx.credentials.Credential {
+ ctor public PasswordCredential(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ field public static final androidx.credentials.PasswordCredential.Companion Companion;
+ field public static final String TYPE_PASSWORD_CREDENTIAL = "android.credentials.TYPE_PASSWORD_CREDENTIAL";
+ }
+
+ public static final class PasswordCredential.Companion {
+ }
+
+ @RequiresApi(34) public final class PrepareGetCredentialResponse {
+ method public kotlin.jvm.functions.Function1<java.lang.String,java.lang.Boolean>? getCredentialTypeDelegate();
+ method public kotlin.jvm.functions.Function0<java.lang.Boolean>? getHasAuthResultsDelegate();
+ method public kotlin.jvm.functions.Function0<java.lang.Boolean>? getHasRemoteResultsDelegate();
+ method public androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle? getPendingGetCredentialHandle();
+ method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) public boolean hasAuthenticationResults();
+ method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) public boolean hasCredentialResults(String credentialType);
+ method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) public boolean hasRemoteResults();
+ method public boolean isNullHandlesForTest();
+ property public final kotlin.jvm.functions.Function1<java.lang.String,java.lang.Boolean>? credentialTypeDelegate;
+ property public final kotlin.jvm.functions.Function0<java.lang.Boolean>? hasAuthResultsDelegate;
+ property public final kotlin.jvm.functions.Function0<java.lang.Boolean>? hasRemoteResultsDelegate;
+ property public final boolean isNullHandlesForTest;
+ property public final androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle? pendingGetCredentialHandle;
+ }
+
+ @RequiresApi(34) public static final class PrepareGetCredentialResponse.PendingGetCredentialHandle {
+ ctor public PrepareGetCredentialResponse.PendingGetCredentialHandle(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle? frameworkHandle);
+ }
+
+ @VisibleForTesting public static final class PrepareGetCredentialResponse.TestBuilder {
+ ctor public PrepareGetCredentialResponse.TestBuilder();
+ method public androidx.credentials.PrepareGetCredentialResponse build();
+ method @VisibleForTesting public androidx.credentials.PrepareGetCredentialResponse.TestBuilder setCredentialTypeDelegate(kotlin.jvm.functions.Function1<? super java.lang.String,java.lang.Boolean> handler);
+ method @VisibleForTesting public androidx.credentials.PrepareGetCredentialResponse.TestBuilder setHasAuthResultsDelegate(kotlin.jvm.functions.Function0<java.lang.Boolean> handler);
+ method @VisibleForTesting public androidx.credentials.PrepareGetCredentialResponse.TestBuilder setHasRemoteResultsDelegate(kotlin.jvm.functions.Function0<java.lang.Boolean> handler);
+ }
+
+ public final class PublicKeyCredential extends androidx.credentials.Credential {
+ ctor public PublicKeyCredential(String authenticationResponseJson);
+ method public String getAuthenticationResponseJson();
+ property public final String authenticationResponseJson;
+ field public static final androidx.credentials.PublicKeyCredential.Companion Companion;
+ field public static final String TYPE_PUBLIC_KEY_CREDENTIAL = "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL";
+ }
+
+ public static final class PublicKeyCredential.Companion {
+ }
+
+}
+
+package androidx.credentials.exceptions {
+
+ public final class ClearCredentialCustomException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialCustomException(String type);
+ ctor public ClearCredentialCustomException(String type, optional CharSequence? errorMessage);
+ method public String getType();
+ property public String type;
+ }
+
+ public abstract class ClearCredentialException extends java.lang.Exception {
+ }
+
+ public final class ClearCredentialInterruptedException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialInterruptedException();
+ ctor public ClearCredentialInterruptedException(optional CharSequence? errorMessage);
+ }
+
+ public final class ClearCredentialProviderConfigurationException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialProviderConfigurationException();
+ ctor public ClearCredentialProviderConfigurationException(optional CharSequence? errorMessage);
+ }
+
+ public final class ClearCredentialUnknownException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialUnknownException();
+ ctor public ClearCredentialUnknownException(optional CharSequence? errorMessage);
+ }
+
+ public final class ClearCredentialUnsupportedException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialUnsupportedException();
+ ctor public ClearCredentialUnsupportedException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialCancellationException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialCancellationException();
+ ctor public CreateCredentialCancellationException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialCustomException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialCustomException(String type);
+ ctor public CreateCredentialCustomException(String type, optional CharSequence? errorMessage);
+ method public String getType();
+ property public String type;
+ }
+
+ public abstract class CreateCredentialException extends java.lang.Exception {
+ }
+
+ public final class CreateCredentialInterruptedException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialInterruptedException();
+ ctor public CreateCredentialInterruptedException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialNoCreateOptionException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialNoCreateOptionException();
+ ctor public CreateCredentialNoCreateOptionException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialProviderConfigurationException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialProviderConfigurationException();
+ ctor public CreateCredentialProviderConfigurationException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialUnknownException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialUnknownException();
+ ctor public CreateCredentialUnknownException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialUnsupportedException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialUnsupportedException();
+ ctor public CreateCredentialUnsupportedException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialCancellationException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialCancellationException();
+ ctor public GetCredentialCancellationException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialCustomException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialCustomException(String type);
+ ctor public GetCredentialCustomException(String type, optional CharSequence? errorMessage);
+ method public String getType();
+ property public String type;
+ }
+
+ public abstract class GetCredentialException extends java.lang.Exception {
+ }
+
+ public final class GetCredentialInterruptedException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialInterruptedException();
+ ctor public GetCredentialInterruptedException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialProviderConfigurationException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialProviderConfigurationException();
+ ctor public GetCredentialProviderConfigurationException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialUnknownException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialUnknownException();
+ ctor public GetCredentialUnknownException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialUnsupportedException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialUnsupportedException();
+ ctor public GetCredentialUnsupportedException(optional CharSequence? errorMessage);
+ }
+
+ public final class NoCredentialException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public NoCredentialException();
+ ctor public NoCredentialException(optional CharSequence? errorMessage);
+ }
+
+}
+
+package androidx.credentials.exceptions.domerrors {
+
+ public final class AbortError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public AbortError();
+ }
+
+ public final class ConstraintError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public ConstraintError();
+ }
+
+ public final class DataCloneError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public DataCloneError();
+ }
+
+ public final class DataError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public DataError();
+ }
+
+ public abstract class DomError {
+ ctor public DomError(String type);
+ }
+
+ public final class EncodingError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public EncodingError();
+ }
+
+ public final class HierarchyRequestError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public HierarchyRequestError();
+ }
+
+ public final class InUseAttributeError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InUseAttributeError();
+ }
+
+ public final class InvalidCharacterError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidCharacterError();
+ }
+
+ public final class InvalidModificationError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidModificationError();
+ }
+
+ public final class InvalidNodeTypeError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidNodeTypeError();
+ }
+
+ public final class InvalidStateError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidStateError();
+ }
+
+ public final class NamespaceError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NamespaceError();
+ }
+
+ public final class NetworkError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NetworkError();
+ }
+
+ public final class NoModificationAllowedError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NoModificationAllowedError();
+ }
+
+ public final class NotAllowedError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotAllowedError();
+ }
+
+ public final class NotFoundError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotFoundError();
+ }
+
+ public final class NotReadableError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotReadableError();
+ }
+
+ public final class NotSupportedError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotSupportedError();
+ }
+
+ public final class OperationError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public OperationError();
+ }
+
+ public final class OptOutError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public OptOutError();
+ }
+
+ public final class QuotaExceededError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public QuotaExceededError();
+ }
+
+ public final class ReadOnlyError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public ReadOnlyError();
+ }
+
+ public final class SecurityError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public SecurityError();
+ }
+
+ public final class SyntaxError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public SyntaxError();
+ }
+
+ public final class TimeoutError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public TimeoutError();
+ }
+
+ public final class TransactionInactiveError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public TransactionInactiveError();
+ }
+
+ public final class UnknownError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public UnknownError();
+ }
+
+ public final class VersionError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public VersionError();
+ }
+
+ public final class WrongDocumentError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public WrongDocumentError();
+ }
+
+}
+
+package androidx.credentials.exceptions.publickeycredential {
+
+ public final class CreatePublicKeyCredentialDomException extends androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialException {
+ ctor public CreatePublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError);
+ ctor public CreatePublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError, optional CharSequence? errorMessage);
+ method public androidx.credentials.exceptions.domerrors.DomError getDomError();
+ property public final androidx.credentials.exceptions.domerrors.DomError domError;
+ }
+
+ public class CreatePublicKeyCredentialException extends androidx.credentials.exceptions.CreateCredentialException {
+ }
+
+ public final class GetPublicKeyCredentialDomException extends androidx.credentials.exceptions.publickeycredential.GetPublicKeyCredentialException {
+ ctor public GetPublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError);
+ ctor public GetPublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError, optional CharSequence? errorMessage);
+ method public androidx.credentials.exceptions.domerrors.DomError getDomError();
+ property public final androidx.credentials.exceptions.domerrors.DomError domError;
+ }
+
+ public class GetPublicKeyCredentialException extends androidx.credentials.exceptions.GetCredentialException {
+ }
+
+}
+
+package androidx.credentials.provider {
+
+ public final class Action {
+ ctor public Action(CharSequence title, android.app.PendingIntent pendingIntent, optional CharSequence? subtitle);
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ }
+
+ public static final class Action.Builder {
+ ctor public Action.Builder(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.Action build();
+ method public androidx.credentials.provider.Action.Builder setSubtitle(CharSequence? subtitle);
+ }
+
+ public final class AuthenticationAction {
+ ctor public AuthenticationAction(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTitle();
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence title;
+ }
+
+ public static final class AuthenticationAction.Builder {
+ ctor public AuthenticationAction.Builder(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.AuthenticationAction build();
+ }
+
+ public abstract class BeginCreateCredentialRequest {
+ ctor public BeginCreateCredentialRequest(String type, android.os.Bundle candidateQueryData, androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ method public static final android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialRequest request);
+ method public static final androidx.credentials.provider.BeginCreateCredentialRequest? fromBundle(android.os.Bundle bundle);
+ method public final androidx.credentials.provider.CallingAppInfo? getCallingAppInfo();
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final String getType();
+ property public final androidx.credentials.provider.CallingAppInfo? callingAppInfo;
+ property public final android.os.Bundle candidateQueryData;
+ property public final String type;
+ field public static final androidx.credentials.provider.BeginCreateCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreateCredentialRequest.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialRequest request);
+ method public androidx.credentials.provider.BeginCreateCredentialRequest? fromBundle(android.os.Bundle bundle);
+ }
+
+ public final class BeginCreateCredentialResponse {
+ ctor public BeginCreateCredentialResponse(optional java.util.List<androidx.credentials.provider.CreateEntry> createEntries, optional androidx.credentials.provider.RemoteEntry? remoteEntry);
+ method public static android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialResponse response);
+ method public static androidx.credentials.provider.BeginCreateCredentialResponse? fromBundle(android.os.Bundle bundle);
+ method public java.util.List<androidx.credentials.provider.CreateEntry> getCreateEntries();
+ method public androidx.credentials.provider.RemoteEntry? getRemoteEntry();
+ property public final java.util.List<androidx.credentials.provider.CreateEntry> createEntries;
+ property public final androidx.credentials.provider.RemoteEntry? remoteEntry;
+ field public static final androidx.credentials.provider.BeginCreateCredentialResponse.Companion Companion;
+ }
+
+ public static final class BeginCreateCredentialResponse.Builder {
+ ctor public BeginCreateCredentialResponse.Builder();
+ method public androidx.credentials.provider.BeginCreateCredentialResponse.Builder addCreateEntry(androidx.credentials.provider.CreateEntry createEntry);
+ method public androidx.credentials.provider.BeginCreateCredentialResponse build();
+ method public androidx.credentials.provider.BeginCreateCredentialResponse.Builder setCreateEntries(java.util.List<androidx.credentials.provider.CreateEntry> createEntries);
+ method public androidx.credentials.provider.BeginCreateCredentialResponse.Builder setRemoteEntry(androidx.credentials.provider.RemoteEntry? remoteEntry);
+ }
+
+ public static final class BeginCreateCredentialResponse.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialResponse response);
+ method public androidx.credentials.provider.BeginCreateCredentialResponse? fromBundle(android.os.Bundle bundle);
+ }
+
+ public class BeginCreateCustomCredentialRequest extends androidx.credentials.provider.BeginCreateCredentialRequest {
+ ctor public BeginCreateCustomCredentialRequest(String type, android.os.Bundle candidateQueryData, androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ }
+
+ public final class BeginCreatePasswordCredentialRequest extends androidx.credentials.provider.BeginCreateCredentialRequest {
+ ctor public BeginCreatePasswordCredentialRequest(androidx.credentials.provider.CallingAppInfo? callingAppInfo, android.os.Bundle candidateQueryData);
+ }
+
+ public final class BeginCreatePublicKeyCredentialRequest extends androidx.credentials.provider.BeginCreateCredentialRequest {
+ ctor public BeginCreatePublicKeyCredentialRequest(String requestJson, androidx.credentials.provider.CallingAppInfo? callingAppInfo, android.os.Bundle candidateQueryData);
+ ctor public BeginCreatePublicKeyCredentialRequest(String requestJson, androidx.credentials.provider.CallingAppInfo? callingAppInfo, android.os.Bundle candidateQueryData, optional byte[]? clientDataHash);
+ method @VisibleForTesting public static androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest createForTest(android.os.Bundle data, androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public abstract class BeginGetCredentialOption {
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final String getId();
+ method public final String getType();
+ property public final android.os.Bundle candidateQueryData;
+ property public final String id;
+ property public final String type;
+ }
+
+ public final class BeginGetCredentialRequest {
+ ctor public BeginGetCredentialRequest(java.util.List<? extends androidx.credentials.provider.BeginGetCredentialOption> beginGetCredentialOptions);
+ ctor public BeginGetCredentialRequest(java.util.List<? extends androidx.credentials.provider.BeginGetCredentialOption> beginGetCredentialOptions, optional androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ method public static android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialRequest request);
+ method public static androidx.credentials.provider.BeginGetCredentialRequest? fromBundle(android.os.Bundle bundle);
+ method public java.util.List<androidx.credentials.provider.BeginGetCredentialOption> getBeginGetCredentialOptions();
+ method public androidx.credentials.provider.CallingAppInfo? getCallingAppInfo();
+ property public final java.util.List<androidx.credentials.provider.BeginGetCredentialOption> beginGetCredentialOptions;
+ property public final androidx.credentials.provider.CallingAppInfo? callingAppInfo;
+ field public static final androidx.credentials.provider.BeginGetCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginGetCredentialRequest.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialRequest request);
+ method public androidx.credentials.provider.BeginGetCredentialRequest? fromBundle(android.os.Bundle bundle);
+ }
+
+ public final class BeginGetCredentialResponse {
+ ctor public BeginGetCredentialResponse(optional java.util.List<? extends androidx.credentials.provider.CredentialEntry> credentialEntries, optional java.util.List<androidx.credentials.provider.Action> actions, optional java.util.List<androidx.credentials.provider.AuthenticationAction> authenticationActions, optional androidx.credentials.provider.RemoteEntry? remoteEntry);
+ method public static android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public static androidx.credentials.provider.BeginGetCredentialResponse? fromBundle(android.os.Bundle bundle);
+ method public java.util.List<androidx.credentials.provider.Action> getActions();
+ method public java.util.List<androidx.credentials.provider.AuthenticationAction> getAuthenticationActions();
+ method public java.util.List<androidx.credentials.provider.CredentialEntry> getCredentialEntries();
+ method public androidx.credentials.provider.RemoteEntry? getRemoteEntry();
+ property public final java.util.List<androidx.credentials.provider.Action> actions;
+ property public final java.util.List<androidx.credentials.provider.AuthenticationAction> authenticationActions;
+ property public final java.util.List<androidx.credentials.provider.CredentialEntry> credentialEntries;
+ property public final androidx.credentials.provider.RemoteEntry? remoteEntry;
+ field public static final androidx.credentials.provider.BeginGetCredentialResponse.Companion Companion;
+ }
+
+ public static final class BeginGetCredentialResponse.Builder {
+ ctor public BeginGetCredentialResponse.Builder();
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder addAction(androidx.credentials.provider.Action action);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder addAuthenticationAction(androidx.credentials.provider.AuthenticationAction authenticationAction);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder addCredentialEntry(androidx.credentials.provider.CredentialEntry entry);
+ method public androidx.credentials.provider.BeginGetCredentialResponse build();
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setActions(java.util.List<androidx.credentials.provider.Action> actions);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setAuthenticationActions(java.util.List<androidx.credentials.provider.AuthenticationAction> authenticationEntries);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setCredentialEntries(java.util.List<? extends androidx.credentials.provider.CredentialEntry> entries);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setRemoteEntry(androidx.credentials.provider.RemoteEntry? remoteEntry);
+ }
+
+ public static final class BeginGetCredentialResponse.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public androidx.credentials.provider.BeginGetCredentialResponse? fromBundle(android.os.Bundle bundle);
+ }
+
+ public class BeginGetCustomCredentialOption extends androidx.credentials.provider.BeginGetCredentialOption {
+ ctor public BeginGetCustomCredentialOption(String id, String type, android.os.Bundle candidateQueryData);
+ }
+
+ public final class BeginGetPasswordOption extends androidx.credentials.provider.BeginGetCredentialOption {
+ ctor public BeginGetPasswordOption(java.util.Set<java.lang.String> allowedUserIds, android.os.Bundle candidateQueryData, String id);
+ method @VisibleForTesting public static androidx.credentials.provider.BeginGetPasswordOption createForTest(android.os.Bundle data, String id);
+ method public java.util.Set<java.lang.String> getAllowedUserIds();
+ property public final java.util.Set<java.lang.String> allowedUserIds;
+ }
+
+ public final class BeginGetPublicKeyCredentialOption extends androidx.credentials.provider.BeginGetCredentialOption {
+ ctor public BeginGetPublicKeyCredentialOption(android.os.Bundle candidateQueryData, String id, String requestJson);
+ ctor public BeginGetPublicKeyCredentialOption(android.os.Bundle candidateQueryData, String id, String requestJson, optional byte[]? clientDataHash);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public final class CallingAppInfo {
+ ctor public CallingAppInfo(String packageName, android.content.pm.SigningInfo signingInfo);
+ ctor public CallingAppInfo(String packageName, android.content.pm.SigningInfo signingInfo, optional String? origin);
+ method public String? getOrigin(String privilegedAllowlist);
+ method public String getPackageName();
+ method public android.content.pm.SigningInfo getSigningInfo();
+ method public boolean isOriginPopulated();
+ property public final String packageName;
+ property public final android.content.pm.SigningInfo signingInfo;
+ }
+
+ @RequiresApi(26) public final class CreateEntry {
+ ctor public CreateEntry(CharSequence accountName, android.app.PendingIntent pendingIntent, optional CharSequence? description, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional Integer? passwordCredentialCount, optional Integer? publicKeyCredentialCount, optional Integer? totalCredentialCount, optional boolean isAutoSelectAllowed);
+ method public CharSequence getAccountName();
+ method public CharSequence? getDescription();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public Integer? getPasswordCredentialCount();
+ method public android.app.PendingIntent getPendingIntent();
+ method public Integer? getPublicKeyCredentialCount();
+ method public Integer? getTotalCredentialCount();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence accountName;
+ property public final CharSequence? description;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ }
+
+ public static final class CreateEntry.Builder {
+ ctor public CreateEntry.Builder(CharSequence accountName, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.CreateEntry build();
+ method public androidx.credentials.provider.CreateEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.CreateEntry.Builder setDescription(CharSequence? description);
+ method public androidx.credentials.provider.CreateEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CreateEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CreateEntry.Builder setPasswordCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setPublicKeyCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setTotalCredentialCount(int count);
+ }
+
+ public abstract class CredentialEntry {
+ method public final androidx.credentials.provider.BeginGetCredentialOption getBeginGetCredentialOption();
+ property public final androidx.credentials.provider.BeginGetCredentialOption beginGetCredentialOption;
+ }
+
+ @RequiresApi(34) public abstract class CredentialProviderService extends android.service.credentials.CredentialProviderService {
+ ctor public CredentialProviderService();
+ method public final void onBeginCreateCredential(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.credentials.CreateCredentialException> callback);
+ method public abstract void onBeginCreateCredentialRequest(androidx.credentials.provider.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<androidx.credentials.provider.BeginCreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method public final void onBeginGetCredential(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,android.credentials.GetCredentialException> callback);
+ method public abstract void onBeginGetCredentialRequest(androidx.credentials.provider.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<androidx.credentials.provider.BeginGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method public final void onClearCredentialState(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException> callback);
+ method public abstract void onClearCredentialStateRequest(androidx.credentials.provider.ProviderClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ }
+
+ @RequiresApi(26) public final class CustomCredentialEntry extends androidx.credentials.provider.CredentialEntry {
+ ctor public CustomCredentialEntry(android.content.Context context, CharSequence title, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetCredentialOption beginGetCredentialOption, optional CharSequence? subtitle, optional CharSequence? typeDisplayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon icon, optional boolean isAutoSelectAllowed);
+ method public android.graphics.drawable.Icon getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ method public String getType();
+ method public CharSequence? getTypeDisplayName();
+ method public boolean isAutoSelectAllowed();
+ property public final android.graphics.drawable.Icon icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ property public String type;
+ property public final CharSequence? typeDisplayName;
+ }
+
+ public static final class CustomCredentialEntry.Builder {
+ ctor public CustomCredentialEntry.Builder(android.content.Context context, String type, CharSequence title, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetCredentialOption beginGetCredentialOption);
+ method public androidx.credentials.provider.CustomCredentialEntry build();
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setIcon(android.graphics.drawable.Icon icon);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setSubtitle(CharSequence? subtitle);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setTypeDisplayName(CharSequence? typeDisplayName);
+ }
+
+ public final class IntentHandlerConverters {
+ method @RequiresApi(34) public static androidx.credentials.provider.BeginGetCredentialResponse? getBeginGetResponse(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.CreateCredentialResponse? getCreateCredentialCredentialResponse(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.CreateCredentialException? getCreateCredentialException(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.GetCredentialException? getGetCredentialException(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.GetCredentialResponse? getGetCredentialResponse(android.content.Intent);
+ }
+
+ @RequiresApi(26) public final class PasswordCredentialEntry extends androidx.credentials.provider.CredentialEntry {
+ ctor public PasswordCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon icon, optional boolean isAutoSelectAllowed);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ }
+
+ public static final class PasswordCredentialEntry.Builder {
+ ctor public PasswordCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption);
+ method public androidx.credentials.provider.PasswordCredentialEntry build();
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setIcon(android.graphics.drawable.Icon icon);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ @RequiresApi(34) public final class PendingIntentHandler {
+ ctor public PendingIntentHandler();
+ method public static androidx.credentials.provider.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public static void setBeginGetCredentialResponse(android.content.Intent intent, androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public static void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public static void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public static void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public static void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ field public static final androidx.credentials.provider.PendingIntentHandler.Companion Companion;
+ }
+
+ public static final class PendingIntentHandler.Companion {
+ method public androidx.credentials.provider.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public void setBeginGetCredentialResponse(android.content.Intent intent, androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ }
+
+ public final class ProviderClearCredentialStateRequest {
+ ctor public ProviderClearCredentialStateRequest(androidx.credentials.provider.CallingAppInfo callingAppInfo);
+ method public androidx.credentials.provider.CallingAppInfo getCallingAppInfo();
+ property public final androidx.credentials.provider.CallingAppInfo callingAppInfo;
+ }
+
+ public final class ProviderCreateCredentialRequest {
+ ctor public ProviderCreateCredentialRequest(androidx.credentials.CreateCredentialRequest callingRequest, androidx.credentials.provider.CallingAppInfo callingAppInfo);
+ method public androidx.credentials.provider.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CreateCredentialRequest getCallingRequest();
+ property public final androidx.credentials.provider.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CreateCredentialRequest callingRequest;
+ }
+
+ public final class ProviderGetCredentialRequest {
+ ctor public ProviderGetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, androidx.credentials.provider.CallingAppInfo callingAppInfo);
+ method public androidx.credentials.provider.CallingAppInfo getCallingAppInfo();
+ method public java.util.List<androidx.credentials.CredentialOption> getCredentialOptions();
+ property public final androidx.credentials.provider.CallingAppInfo callingAppInfo;
+ property public final java.util.List<androidx.credentials.CredentialOption> credentialOptions;
+ }
+
+ @RequiresApi(26) public final class PublicKeyCredentialEntry extends androidx.credentials.provider.CredentialEntry {
+ ctor public PublicKeyCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon icon, optional boolean isAutoSelectAllowed);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ }
+
+ public static final class PublicKeyCredentialEntry.Builder {
+ ctor public PublicKeyCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry build();
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setIcon(android.graphics.drawable.Icon icon);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public final class RemoteEntry {
+ ctor public RemoteEntry(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ }
+
+ public static final class RemoteEntry.Builder {
+ ctor public RemoteEntry.Builder(android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.RemoteEntry build();
+ }
+
+}
+
diff --git a/credentials/credentials/api/res-1.2.0-beta02.txt b/credentials/credentials/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/credentials/credentials/api/res-1.2.0-beta02.txt
diff --git a/credentials/credentials/api/restricted_1.2.0-beta02.txt b/credentials/credentials/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..8c9cf86
--- /dev/null
+++ b/credentials/credentials/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,902 @@
+// Signature format: 4.0
+package androidx.credentials {
+
+ public final class ClearCredentialStateRequest {
+ ctor public ClearCredentialStateRequest();
+ }
+
+ public abstract class CreateCredentialRequest {
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final android.os.Bundle getCredentialData();
+ method public final androidx.credentials.CreateCredentialRequest.DisplayInfo getDisplayInfo();
+ method public final String? getOrigin();
+ method public final boolean getPreferImmediatelyAvailableCredentials();
+ method public final String getType();
+ method public final boolean isAutoSelectAllowed();
+ method public final boolean isSystemProviderRequired();
+ property public final android.os.Bundle candidateQueryData;
+ property public final android.os.Bundle credentialData;
+ property public final androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo;
+ property public final boolean isAutoSelectAllowed;
+ property public final boolean isSystemProviderRequired;
+ property public final String? origin;
+ property public final boolean preferImmediatelyAvailableCredentials;
+ property public final String type;
+ }
+
+ public static final class CreateCredentialRequest.DisplayInfo {
+ ctor public CreateCredentialRequest.DisplayInfo(CharSequence userId);
+ ctor public CreateCredentialRequest.DisplayInfo(CharSequence userId, optional CharSequence? userDisplayName);
+ ctor public CreateCredentialRequest.DisplayInfo(CharSequence userId, CharSequence? userDisplayName, String? preferDefaultProvider);
+ method public CharSequence? getUserDisplayName();
+ method public CharSequence getUserId();
+ property public final CharSequence? userDisplayName;
+ property public final CharSequence userId;
+ }
+
+ public abstract class CreateCredentialResponse {
+ method public final android.os.Bundle getData();
+ method public final String getType();
+ property public final android.os.Bundle data;
+ property public final String type;
+ }
+
+ public class CreateCustomCredentialRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo);
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo, optional boolean isAutoSelectAllowed);
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo, optional boolean isAutoSelectAllowed, optional String? origin);
+ ctor public CreateCustomCredentialRequest(String type, android.os.Bundle credentialData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, androidx.credentials.CreateCredentialRequest.DisplayInfo displayInfo, optional boolean isAutoSelectAllowed, optional String? origin, optional boolean preferImmediatelyAvailableCredentials);
+ }
+
+ public class CreateCustomCredentialResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreateCustomCredentialResponse(String type, android.os.Bundle data);
+ }
+
+ public final class CreatePasswordRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreatePasswordRequest(String id, String password);
+ ctor public CreatePasswordRequest(String id, String password, optional String? origin);
+ ctor public CreatePasswordRequest(String id, String password, optional String? origin, optional boolean preferImmediatelyAvailableCredentials);
+ ctor public CreatePasswordRequest(String id, String password, optional String? origin, optional boolean preferImmediatelyAvailableCredentials, optional boolean isAutoSelectAllowed);
+ ctor public CreatePasswordRequest(String id, String password, String? origin, String? preferDefaultProvider, boolean preferImmediatelyAvailableCredentials, boolean isAutoSelectAllowed);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ }
+
+ public final class CreatePasswordResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreatePasswordResponse();
+ }
+
+ public final class CreatePublicKeyCredentialRequest extends androidx.credentials.CreateCredentialRequest {
+ ctor public CreatePublicKeyCredentialRequest(String requestJson);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash, optional boolean preferImmediatelyAvailableCredentials);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash, optional boolean preferImmediatelyAvailableCredentials, optional String? origin);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, optional byte[]? clientDataHash, optional boolean preferImmediatelyAvailableCredentials, optional String? origin, optional boolean isAutoSelectAllowed);
+ ctor public CreatePublicKeyCredentialRequest(String requestJson, byte[]? clientDataHash, boolean preferImmediatelyAvailableCredentials, String? origin, String? preferDefaultProvider, boolean isAutoSelectAllowed);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public final class CreatePublicKeyCredentialResponse extends androidx.credentials.CreateCredentialResponse {
+ ctor public CreatePublicKeyCredentialResponse(String registrationResponseJson);
+ method public String getRegistrationResponseJson();
+ property public final String registrationResponseJson;
+ }
+
+ public abstract class Credential {
+ method public final android.os.Bundle getData();
+ method public final String getType();
+ property public final android.os.Bundle data;
+ property public final String type;
+ }
+
+ @RequiresApi(16) public interface CredentialManager {
+ method public default suspend Object? clearCredentialState(androidx.credentials.ClearCredentialStateRequest request, kotlin.coroutines.Continuation<? super kotlin.Unit>);
+ method public void clearCredentialStateAsync(androidx.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ method public static androidx.credentials.CredentialManager create(android.content.Context context);
+ method public default suspend Object? createCredential(android.content.Context context, androidx.credentials.CreateCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.CreateCredentialResponse>);
+ method public void createCredentialAsync(android.content.Context context, androidx.credentials.CreateCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.CreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method @RequiresApi(34) public android.app.PendingIntent createSettingsPendingIntent();
+ method public default suspend Object? getCredential(android.content.Context context, androidx.credentials.GetCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.GetCredentialResponse>);
+ method @RequiresApi(34) public default suspend Object? getCredential(android.content.Context context, androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle pendingGetCredentialHandle, kotlin.coroutines.Continuation<? super androidx.credentials.GetCredentialResponse>);
+ method public void getCredentialAsync(android.content.Context context, androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public void getCredentialAsync(android.content.Context context, androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle pendingGetCredentialHandle, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public default suspend Object? prepareGetCredential(androidx.credentials.GetCredentialRequest request, kotlin.coroutines.Continuation<? super androidx.credentials.PrepareGetCredentialResponse>);
+ method @RequiresApi(34) public void prepareGetCredentialAsync(androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.PrepareGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ field public static final androidx.credentials.CredentialManager.Companion Companion;
+ }
+
+ public static final class CredentialManager.Companion {
+ method public androidx.credentials.CredentialManager create(android.content.Context context);
+ }
+
+ public interface CredentialManagerCallback<R, E> {
+ method public void onError(E e);
+ method public void onResult(R result);
+ }
+
+ public abstract class CredentialOption {
+ method public final java.util.Set<android.content.ComponentName> getAllowedProviders();
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final android.os.Bundle getRequestData();
+ method public final String getType();
+ method public final boolean isAutoSelectAllowed();
+ method public final boolean isSystemProviderRequired();
+ property public final java.util.Set<android.content.ComponentName> allowedProviders;
+ property public final android.os.Bundle candidateQueryData;
+ property public final boolean isAutoSelectAllowed;
+ property public final boolean isSystemProviderRequired;
+ property public final android.os.Bundle requestData;
+ property public final String type;
+ }
+
+ public interface CredentialProvider {
+ method public boolean isAvailableOnDevice();
+ method public void onClearCredential(androidx.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ method public void onCreateCredential(android.content.Context context, androidx.credentials.CreateCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.CreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method public void onGetCredential(android.content.Context context, androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public default void onGetCredential(android.content.Context context, androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle pendingGetCredentialHandle, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.GetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method @RequiresApi(34) public default void onPrepareCredential(androidx.credentials.GetCredentialRequest request, android.os.CancellationSignal? cancellationSignal, java.util.concurrent.Executor executor, androidx.credentials.CredentialManagerCallback<androidx.credentials.PrepareGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ }
+
+ public class CustomCredential extends androidx.credentials.Credential {
+ ctor public CustomCredential(String type, android.os.Bundle data);
+ }
+
+ public final class GetCredentialRequest {
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin, optional boolean preferIdentityDocUi);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin, optional boolean preferIdentityDocUi, optional android.content.ComponentName? preferUiBrandingComponentName);
+ ctor public GetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, optional String? origin, optional boolean preferIdentityDocUi, optional android.content.ComponentName? preferUiBrandingComponentName, optional boolean preferImmediatelyAvailableCredentials);
+ method public java.util.List<androidx.credentials.CredentialOption> getCredentialOptions();
+ method public String? getOrigin();
+ method public boolean getPreferIdentityDocUi();
+ method public boolean getPreferImmediatelyAvailableCredentials();
+ method public android.content.ComponentName? getPreferUiBrandingComponentName();
+ property public final java.util.List<androidx.credentials.CredentialOption> credentialOptions;
+ property public final String? origin;
+ property public final boolean preferIdentityDocUi;
+ property public final boolean preferImmediatelyAvailableCredentials;
+ property public final android.content.ComponentName? preferUiBrandingComponentName;
+ }
+
+ public static final class GetCredentialRequest.Builder {
+ ctor public GetCredentialRequest.Builder();
+ method public androidx.credentials.GetCredentialRequest.Builder addCredentialOption(androidx.credentials.CredentialOption credentialOption);
+ method public androidx.credentials.GetCredentialRequest build();
+ method public androidx.credentials.GetCredentialRequest.Builder setCredentialOptions(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions);
+ method public androidx.credentials.GetCredentialRequest.Builder setOrigin(String origin);
+ method public androidx.credentials.GetCredentialRequest.Builder setPreferIdentityDocUi(boolean preferIdentityDocUi);
+ method public androidx.credentials.GetCredentialRequest.Builder setPreferImmediatelyAvailableCredentials(boolean preferImmediatelyAvailableCredentials);
+ method public androidx.credentials.GetCredentialRequest.Builder setPreferUiBrandingComponentName(android.content.ComponentName? component);
+ }
+
+ public final class GetCredentialResponse {
+ ctor public GetCredentialResponse(androidx.credentials.Credential credential);
+ method public androidx.credentials.Credential getCredential();
+ property public final androidx.credentials.Credential credential;
+ }
+
+ public class GetCustomCredentialOption extends androidx.credentials.CredentialOption {
+ ctor public GetCustomCredentialOption(String type, android.os.Bundle requestData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired);
+ ctor public GetCustomCredentialOption(String type, android.os.Bundle requestData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, optional boolean isAutoSelectAllowed);
+ ctor public GetCustomCredentialOption(String type, android.os.Bundle requestData, android.os.Bundle candidateQueryData, boolean isSystemProviderRequired, optional boolean isAutoSelectAllowed, optional java.util.Set<android.content.ComponentName> allowedProviders);
+ }
+
+ public final class GetPasswordOption extends androidx.credentials.CredentialOption {
+ ctor public GetPasswordOption();
+ ctor public GetPasswordOption(optional java.util.Set<java.lang.String> allowedUserIds);
+ ctor public GetPasswordOption(optional java.util.Set<java.lang.String> allowedUserIds, optional boolean isAutoSelectAllowed);
+ ctor public GetPasswordOption(optional java.util.Set<java.lang.String> allowedUserIds, optional boolean isAutoSelectAllowed, optional java.util.Set<android.content.ComponentName> allowedProviders);
+ method public java.util.Set<java.lang.String> getAllowedUserIds();
+ property public final java.util.Set<java.lang.String> allowedUserIds;
+ }
+
+ public final class GetPublicKeyCredentialOption extends androidx.credentials.CredentialOption {
+ ctor public GetPublicKeyCredentialOption(String requestJson);
+ ctor public GetPublicKeyCredentialOption(String requestJson, optional byte[]? clientDataHash);
+ ctor public GetPublicKeyCredentialOption(String requestJson, optional byte[]? clientDataHash, optional java.util.Set<android.content.ComponentName> allowedProviders);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public final class PasswordCredential extends androidx.credentials.Credential {
+ ctor public PasswordCredential(String id, String password);
+ method public String getId();
+ method public String getPassword();
+ property public final String id;
+ property public final String password;
+ field public static final androidx.credentials.PasswordCredential.Companion Companion;
+ field public static final String TYPE_PASSWORD_CREDENTIAL = "android.credentials.TYPE_PASSWORD_CREDENTIAL";
+ }
+
+ public static final class PasswordCredential.Companion {
+ }
+
+ @RequiresApi(34) public final class PrepareGetCredentialResponse {
+ method public kotlin.jvm.functions.Function1<java.lang.String,java.lang.Boolean>? getCredentialTypeDelegate();
+ method public kotlin.jvm.functions.Function0<java.lang.Boolean>? getHasAuthResultsDelegate();
+ method public kotlin.jvm.functions.Function0<java.lang.Boolean>? getHasRemoteResultsDelegate();
+ method public androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle? getPendingGetCredentialHandle();
+ method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) public boolean hasAuthenticationResults();
+ method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) public boolean hasCredentialResults(String credentialType);
+ method @RequiresPermission(android.Manifest.permission.CREDENTIAL_MANAGER_QUERY_CANDIDATE_CREDENTIALS) public boolean hasRemoteResults();
+ method public boolean isNullHandlesForTest();
+ property public final kotlin.jvm.functions.Function1<java.lang.String,java.lang.Boolean>? credentialTypeDelegate;
+ property public final kotlin.jvm.functions.Function0<java.lang.Boolean>? hasAuthResultsDelegate;
+ property public final kotlin.jvm.functions.Function0<java.lang.Boolean>? hasRemoteResultsDelegate;
+ property public final boolean isNullHandlesForTest;
+ property public final androidx.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle? pendingGetCredentialHandle;
+ }
+
+ @RequiresApi(34) public static final class PrepareGetCredentialResponse.PendingGetCredentialHandle {
+ ctor public PrepareGetCredentialResponse.PendingGetCredentialHandle(android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle? frameworkHandle);
+ }
+
+ @VisibleForTesting public static final class PrepareGetCredentialResponse.TestBuilder {
+ ctor public PrepareGetCredentialResponse.TestBuilder();
+ method public androidx.credentials.PrepareGetCredentialResponse build();
+ method @VisibleForTesting public androidx.credentials.PrepareGetCredentialResponse.TestBuilder setCredentialTypeDelegate(kotlin.jvm.functions.Function1<? super java.lang.String,java.lang.Boolean> handler);
+ method @VisibleForTesting public androidx.credentials.PrepareGetCredentialResponse.TestBuilder setHasAuthResultsDelegate(kotlin.jvm.functions.Function0<java.lang.Boolean> handler);
+ method @VisibleForTesting public androidx.credentials.PrepareGetCredentialResponse.TestBuilder setHasRemoteResultsDelegate(kotlin.jvm.functions.Function0<java.lang.Boolean> handler);
+ }
+
+ public final class PublicKeyCredential extends androidx.credentials.Credential {
+ ctor public PublicKeyCredential(String authenticationResponseJson);
+ method public String getAuthenticationResponseJson();
+ property public final String authenticationResponseJson;
+ field public static final androidx.credentials.PublicKeyCredential.Companion Companion;
+ field public static final String TYPE_PUBLIC_KEY_CREDENTIAL = "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL";
+ }
+
+ public static final class PublicKeyCredential.Companion {
+ }
+
+}
+
+package androidx.credentials.exceptions {
+
+ public final class ClearCredentialCustomException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialCustomException(String type);
+ ctor public ClearCredentialCustomException(String type, optional CharSequence? errorMessage);
+ method public String getType();
+ property public String type;
+ }
+
+ public abstract class ClearCredentialException extends java.lang.Exception {
+ }
+
+ public final class ClearCredentialInterruptedException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialInterruptedException();
+ ctor public ClearCredentialInterruptedException(optional CharSequence? errorMessage);
+ }
+
+ public final class ClearCredentialProviderConfigurationException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialProviderConfigurationException();
+ ctor public ClearCredentialProviderConfigurationException(optional CharSequence? errorMessage);
+ }
+
+ public final class ClearCredentialUnknownException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialUnknownException();
+ ctor public ClearCredentialUnknownException(optional CharSequence? errorMessage);
+ }
+
+ public final class ClearCredentialUnsupportedException extends androidx.credentials.exceptions.ClearCredentialException {
+ ctor public ClearCredentialUnsupportedException();
+ ctor public ClearCredentialUnsupportedException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialCancellationException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialCancellationException();
+ ctor public CreateCredentialCancellationException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialCustomException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialCustomException(String type);
+ ctor public CreateCredentialCustomException(String type, optional CharSequence? errorMessage);
+ method public String getType();
+ property public String type;
+ }
+
+ public abstract class CreateCredentialException extends java.lang.Exception {
+ }
+
+ public final class CreateCredentialInterruptedException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialInterruptedException();
+ ctor public CreateCredentialInterruptedException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialNoCreateOptionException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialNoCreateOptionException();
+ ctor public CreateCredentialNoCreateOptionException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialProviderConfigurationException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialProviderConfigurationException();
+ ctor public CreateCredentialProviderConfigurationException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialUnknownException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialUnknownException();
+ ctor public CreateCredentialUnknownException(optional CharSequence? errorMessage);
+ }
+
+ public final class CreateCredentialUnsupportedException extends androidx.credentials.exceptions.CreateCredentialException {
+ ctor public CreateCredentialUnsupportedException();
+ ctor public CreateCredentialUnsupportedException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialCancellationException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialCancellationException();
+ ctor public GetCredentialCancellationException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialCustomException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialCustomException(String type);
+ ctor public GetCredentialCustomException(String type, optional CharSequence? errorMessage);
+ method public String getType();
+ property public String type;
+ }
+
+ public abstract class GetCredentialException extends java.lang.Exception {
+ }
+
+ public final class GetCredentialInterruptedException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialInterruptedException();
+ ctor public GetCredentialInterruptedException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialProviderConfigurationException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialProviderConfigurationException();
+ ctor public GetCredentialProviderConfigurationException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialUnknownException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialUnknownException();
+ ctor public GetCredentialUnknownException(optional CharSequence? errorMessage);
+ }
+
+ public final class GetCredentialUnsupportedException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public GetCredentialUnsupportedException();
+ ctor public GetCredentialUnsupportedException(optional CharSequence? errorMessage);
+ }
+
+ public final class NoCredentialException extends androidx.credentials.exceptions.GetCredentialException {
+ ctor public NoCredentialException();
+ ctor public NoCredentialException(optional CharSequence? errorMessage);
+ }
+
+}
+
+package androidx.credentials.exceptions.domerrors {
+
+ public final class AbortError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public AbortError();
+ }
+
+ public final class ConstraintError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public ConstraintError();
+ }
+
+ public final class DataCloneError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public DataCloneError();
+ }
+
+ public final class DataError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public DataError();
+ }
+
+ public abstract class DomError {
+ ctor public DomError(String type);
+ }
+
+ public final class EncodingError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public EncodingError();
+ }
+
+ public final class HierarchyRequestError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public HierarchyRequestError();
+ }
+
+ public final class InUseAttributeError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InUseAttributeError();
+ }
+
+ public final class InvalidCharacterError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidCharacterError();
+ }
+
+ public final class InvalidModificationError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidModificationError();
+ }
+
+ public final class InvalidNodeTypeError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidNodeTypeError();
+ }
+
+ public final class InvalidStateError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public InvalidStateError();
+ }
+
+ public final class NamespaceError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NamespaceError();
+ }
+
+ public final class NetworkError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NetworkError();
+ }
+
+ public final class NoModificationAllowedError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NoModificationAllowedError();
+ }
+
+ public final class NotAllowedError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotAllowedError();
+ }
+
+ public final class NotFoundError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotFoundError();
+ }
+
+ public final class NotReadableError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotReadableError();
+ }
+
+ public final class NotSupportedError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public NotSupportedError();
+ }
+
+ public final class OperationError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public OperationError();
+ }
+
+ public final class OptOutError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public OptOutError();
+ }
+
+ public final class QuotaExceededError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public QuotaExceededError();
+ }
+
+ public final class ReadOnlyError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public ReadOnlyError();
+ }
+
+ public final class SecurityError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public SecurityError();
+ }
+
+ public final class SyntaxError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public SyntaxError();
+ }
+
+ public final class TimeoutError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public TimeoutError();
+ }
+
+ public final class TransactionInactiveError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public TransactionInactiveError();
+ }
+
+ public final class UnknownError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public UnknownError();
+ }
+
+ public final class VersionError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public VersionError();
+ }
+
+ public final class WrongDocumentError extends androidx.credentials.exceptions.domerrors.DomError {
+ ctor public WrongDocumentError();
+ }
+
+}
+
+package androidx.credentials.exceptions.publickeycredential {
+
+ public final class CreatePublicKeyCredentialDomException extends androidx.credentials.exceptions.publickeycredential.CreatePublicKeyCredentialException {
+ ctor public CreatePublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError);
+ ctor public CreatePublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError, optional CharSequence? errorMessage);
+ method public androidx.credentials.exceptions.domerrors.DomError getDomError();
+ property public final androidx.credentials.exceptions.domerrors.DomError domError;
+ }
+
+ public class CreatePublicKeyCredentialException extends androidx.credentials.exceptions.CreateCredentialException {
+ }
+
+ public final class GetPublicKeyCredentialDomException extends androidx.credentials.exceptions.publickeycredential.GetPublicKeyCredentialException {
+ ctor public GetPublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError);
+ ctor public GetPublicKeyCredentialDomException(androidx.credentials.exceptions.domerrors.DomError domError, optional CharSequence? errorMessage);
+ method public androidx.credentials.exceptions.domerrors.DomError getDomError();
+ property public final androidx.credentials.exceptions.domerrors.DomError domError;
+ }
+
+ public class GetPublicKeyCredentialException extends androidx.credentials.exceptions.GetCredentialException {
+ }
+
+}
+
+package androidx.credentials.provider {
+
+ public final class Action {
+ ctor public Action(CharSequence title, android.app.PendingIntent pendingIntent, optional CharSequence? subtitle);
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ }
+
+ public static final class Action.Builder {
+ ctor public Action.Builder(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.Action build();
+ method public androidx.credentials.provider.Action.Builder setSubtitle(CharSequence? subtitle);
+ }
+
+ public final class AuthenticationAction {
+ ctor public AuthenticationAction(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTitle();
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence title;
+ }
+
+ public static final class AuthenticationAction.Builder {
+ ctor public AuthenticationAction.Builder(CharSequence title, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.AuthenticationAction build();
+ }
+
+ public abstract class BeginCreateCredentialRequest {
+ ctor public BeginCreateCredentialRequest(String type, android.os.Bundle candidateQueryData, androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ method public static final android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialRequest request);
+ method public static final androidx.credentials.provider.BeginCreateCredentialRequest? fromBundle(android.os.Bundle bundle);
+ method public final androidx.credentials.provider.CallingAppInfo? getCallingAppInfo();
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final String getType();
+ property public final androidx.credentials.provider.CallingAppInfo? callingAppInfo;
+ property public final android.os.Bundle candidateQueryData;
+ property public final String type;
+ field public static final androidx.credentials.provider.BeginCreateCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginCreateCredentialRequest.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialRequest request);
+ method public androidx.credentials.provider.BeginCreateCredentialRequest? fromBundle(android.os.Bundle bundle);
+ }
+
+ public final class BeginCreateCredentialResponse {
+ ctor public BeginCreateCredentialResponse(optional java.util.List<androidx.credentials.provider.CreateEntry> createEntries, optional androidx.credentials.provider.RemoteEntry? remoteEntry);
+ method public static android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialResponse response);
+ method public static androidx.credentials.provider.BeginCreateCredentialResponse? fromBundle(android.os.Bundle bundle);
+ method public java.util.List<androidx.credentials.provider.CreateEntry> getCreateEntries();
+ method public androidx.credentials.provider.RemoteEntry? getRemoteEntry();
+ property public final java.util.List<androidx.credentials.provider.CreateEntry> createEntries;
+ property public final androidx.credentials.provider.RemoteEntry? remoteEntry;
+ field public static final androidx.credentials.provider.BeginCreateCredentialResponse.Companion Companion;
+ }
+
+ public static final class BeginCreateCredentialResponse.Builder {
+ ctor public BeginCreateCredentialResponse.Builder();
+ method public androidx.credentials.provider.BeginCreateCredentialResponse.Builder addCreateEntry(androidx.credentials.provider.CreateEntry createEntry);
+ method public androidx.credentials.provider.BeginCreateCredentialResponse build();
+ method public androidx.credentials.provider.BeginCreateCredentialResponse.Builder setCreateEntries(java.util.List<androidx.credentials.provider.CreateEntry> createEntries);
+ method public androidx.credentials.provider.BeginCreateCredentialResponse.Builder setRemoteEntry(androidx.credentials.provider.RemoteEntry? remoteEntry);
+ }
+
+ public static final class BeginCreateCredentialResponse.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginCreateCredentialResponse response);
+ method public androidx.credentials.provider.BeginCreateCredentialResponse? fromBundle(android.os.Bundle bundle);
+ }
+
+ public class BeginCreateCustomCredentialRequest extends androidx.credentials.provider.BeginCreateCredentialRequest {
+ ctor public BeginCreateCustomCredentialRequest(String type, android.os.Bundle candidateQueryData, androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ }
+
+ public final class BeginCreatePasswordCredentialRequest extends androidx.credentials.provider.BeginCreateCredentialRequest {
+ ctor public BeginCreatePasswordCredentialRequest(androidx.credentials.provider.CallingAppInfo? callingAppInfo, android.os.Bundle candidateQueryData);
+ }
+
+ public final class BeginCreatePublicKeyCredentialRequest extends androidx.credentials.provider.BeginCreateCredentialRequest {
+ ctor public BeginCreatePublicKeyCredentialRequest(String requestJson, androidx.credentials.provider.CallingAppInfo? callingAppInfo, android.os.Bundle candidateQueryData);
+ ctor public BeginCreatePublicKeyCredentialRequest(String requestJson, androidx.credentials.provider.CallingAppInfo? callingAppInfo, android.os.Bundle candidateQueryData, optional byte[]? clientDataHash);
+ method @VisibleForTesting public static androidx.credentials.provider.BeginCreatePublicKeyCredentialRequest createForTest(android.os.Bundle data, androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public abstract class BeginGetCredentialOption {
+ method public final android.os.Bundle getCandidateQueryData();
+ method public final String getId();
+ method public final String getType();
+ property public final android.os.Bundle candidateQueryData;
+ property public final String id;
+ property public final String type;
+ }
+
+ public final class BeginGetCredentialRequest {
+ ctor public BeginGetCredentialRequest(java.util.List<? extends androidx.credentials.provider.BeginGetCredentialOption> beginGetCredentialOptions);
+ ctor public BeginGetCredentialRequest(java.util.List<? extends androidx.credentials.provider.BeginGetCredentialOption> beginGetCredentialOptions, optional androidx.credentials.provider.CallingAppInfo? callingAppInfo);
+ method public static android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialRequest request);
+ method public static androidx.credentials.provider.BeginGetCredentialRequest? fromBundle(android.os.Bundle bundle);
+ method public java.util.List<androidx.credentials.provider.BeginGetCredentialOption> getBeginGetCredentialOptions();
+ method public androidx.credentials.provider.CallingAppInfo? getCallingAppInfo();
+ property public final java.util.List<androidx.credentials.provider.BeginGetCredentialOption> beginGetCredentialOptions;
+ property public final androidx.credentials.provider.CallingAppInfo? callingAppInfo;
+ field public static final androidx.credentials.provider.BeginGetCredentialRequest.Companion Companion;
+ }
+
+ public static final class BeginGetCredentialRequest.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialRequest request);
+ method public androidx.credentials.provider.BeginGetCredentialRequest? fromBundle(android.os.Bundle bundle);
+ }
+
+ public final class BeginGetCredentialResponse {
+ ctor public BeginGetCredentialResponse(optional java.util.List<? extends androidx.credentials.provider.CredentialEntry> credentialEntries, optional java.util.List<androidx.credentials.provider.Action> actions, optional java.util.List<androidx.credentials.provider.AuthenticationAction> authenticationActions, optional androidx.credentials.provider.RemoteEntry? remoteEntry);
+ method public static android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public static androidx.credentials.provider.BeginGetCredentialResponse? fromBundle(android.os.Bundle bundle);
+ method public java.util.List<androidx.credentials.provider.Action> getActions();
+ method public java.util.List<androidx.credentials.provider.AuthenticationAction> getAuthenticationActions();
+ method public java.util.List<androidx.credentials.provider.CredentialEntry> getCredentialEntries();
+ method public androidx.credentials.provider.RemoteEntry? getRemoteEntry();
+ property public final java.util.List<androidx.credentials.provider.Action> actions;
+ property public final java.util.List<androidx.credentials.provider.AuthenticationAction> authenticationActions;
+ property public final java.util.List<androidx.credentials.provider.CredentialEntry> credentialEntries;
+ property public final androidx.credentials.provider.RemoteEntry? remoteEntry;
+ field public static final androidx.credentials.provider.BeginGetCredentialResponse.Companion Companion;
+ }
+
+ public static final class BeginGetCredentialResponse.Builder {
+ ctor public BeginGetCredentialResponse.Builder();
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder addAction(androidx.credentials.provider.Action action);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder addAuthenticationAction(androidx.credentials.provider.AuthenticationAction authenticationAction);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder addCredentialEntry(androidx.credentials.provider.CredentialEntry entry);
+ method public androidx.credentials.provider.BeginGetCredentialResponse build();
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setActions(java.util.List<androidx.credentials.provider.Action> actions);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setAuthenticationActions(java.util.List<androidx.credentials.provider.AuthenticationAction> authenticationEntries);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setCredentialEntries(java.util.List<? extends androidx.credentials.provider.CredentialEntry> entries);
+ method public androidx.credentials.provider.BeginGetCredentialResponse.Builder setRemoteEntry(androidx.credentials.provider.RemoteEntry? remoteEntry);
+ }
+
+ public static final class BeginGetCredentialResponse.Companion {
+ method public android.os.Bundle asBundle(androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public androidx.credentials.provider.BeginGetCredentialResponse? fromBundle(android.os.Bundle bundle);
+ }
+
+ public class BeginGetCustomCredentialOption extends androidx.credentials.provider.BeginGetCredentialOption {
+ ctor public BeginGetCustomCredentialOption(String id, String type, android.os.Bundle candidateQueryData);
+ }
+
+ public final class BeginGetPasswordOption extends androidx.credentials.provider.BeginGetCredentialOption {
+ ctor public BeginGetPasswordOption(java.util.Set<java.lang.String> allowedUserIds, android.os.Bundle candidateQueryData, String id);
+ method @VisibleForTesting public static androidx.credentials.provider.BeginGetPasswordOption createForTest(android.os.Bundle data, String id);
+ method public java.util.Set<java.lang.String> getAllowedUserIds();
+ property public final java.util.Set<java.lang.String> allowedUserIds;
+ }
+
+ public final class BeginGetPublicKeyCredentialOption extends androidx.credentials.provider.BeginGetCredentialOption {
+ ctor public BeginGetPublicKeyCredentialOption(android.os.Bundle candidateQueryData, String id, String requestJson);
+ ctor public BeginGetPublicKeyCredentialOption(android.os.Bundle candidateQueryData, String id, String requestJson, optional byte[]? clientDataHash);
+ method public byte[]? getClientDataHash();
+ method public String getRequestJson();
+ property public final byte[]? clientDataHash;
+ property public final String requestJson;
+ }
+
+ public final class CallingAppInfo {
+ ctor public CallingAppInfo(String packageName, android.content.pm.SigningInfo signingInfo);
+ ctor public CallingAppInfo(String packageName, android.content.pm.SigningInfo signingInfo, optional String? origin);
+ method public String? getOrigin(String privilegedAllowlist);
+ method public String getPackageName();
+ method public android.content.pm.SigningInfo getSigningInfo();
+ method public boolean isOriginPopulated();
+ property public final String packageName;
+ property public final android.content.pm.SigningInfo signingInfo;
+ }
+
+ @RequiresApi(26) public final class CreateEntry {
+ ctor public CreateEntry(CharSequence accountName, android.app.PendingIntent pendingIntent, optional CharSequence? description, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon? icon, optional Integer? passwordCredentialCount, optional Integer? publicKeyCredentialCount, optional Integer? totalCredentialCount, optional boolean isAutoSelectAllowed);
+ method public CharSequence getAccountName();
+ method public CharSequence? getDescription();
+ method public android.graphics.drawable.Icon? getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public Integer? getPasswordCredentialCount();
+ method public android.app.PendingIntent getPendingIntent();
+ method public Integer? getPublicKeyCredentialCount();
+ method public Integer? getTotalCredentialCount();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence accountName;
+ property public final CharSequence? description;
+ property public final android.graphics.drawable.Icon? icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ }
+
+ public static final class CreateEntry.Builder {
+ ctor public CreateEntry.Builder(CharSequence accountName, android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.CreateEntry build();
+ method public androidx.credentials.provider.CreateEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.CreateEntry.Builder setDescription(CharSequence? description);
+ method public androidx.credentials.provider.CreateEntry.Builder setIcon(android.graphics.drawable.Icon? icon);
+ method public androidx.credentials.provider.CreateEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CreateEntry.Builder setPasswordCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setPublicKeyCredentialCount(int count);
+ method public androidx.credentials.provider.CreateEntry.Builder setTotalCredentialCount(int count);
+ }
+
+ public abstract class CredentialEntry {
+ method public final androidx.credentials.provider.BeginGetCredentialOption getBeginGetCredentialOption();
+ property public final androidx.credentials.provider.BeginGetCredentialOption beginGetCredentialOption;
+ }
+
+ @RequiresApi(34) public abstract class CredentialProviderService extends android.service.credentials.CredentialProviderService {
+ ctor public CredentialProviderService();
+ method public final void onBeginCreateCredential(android.service.credentials.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.credentials.CreateCredentialException> callback);
+ method public abstract void onBeginCreateCredentialRequest(androidx.credentials.provider.BeginCreateCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<androidx.credentials.provider.BeginCreateCredentialResponse,androidx.credentials.exceptions.CreateCredentialException> callback);
+ method public final void onBeginGetCredential(android.service.credentials.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<android.service.credentials.BeginGetCredentialResponse,android.credentials.GetCredentialException> callback);
+ method public abstract void onBeginGetCredentialRequest(androidx.credentials.provider.BeginGetCredentialRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<androidx.credentials.provider.BeginGetCredentialResponse,androidx.credentials.exceptions.GetCredentialException> callback);
+ method public final void onClearCredentialState(android.service.credentials.ClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,android.credentials.ClearCredentialStateException> callback);
+ method public abstract void onClearCredentialStateRequest(androidx.credentials.provider.ProviderClearCredentialStateRequest request, android.os.CancellationSignal cancellationSignal, android.os.OutcomeReceiver<java.lang.Void,androidx.credentials.exceptions.ClearCredentialException> callback);
+ }
+
+ @RequiresApi(26) public final class CustomCredentialEntry extends androidx.credentials.provider.CredentialEntry {
+ ctor public CustomCredentialEntry(android.content.Context context, CharSequence title, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetCredentialOption beginGetCredentialOption, optional CharSequence? subtitle, optional CharSequence? typeDisplayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon icon, optional boolean isAutoSelectAllowed);
+ method public android.graphics.drawable.Icon getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence? getSubtitle();
+ method public CharSequence getTitle();
+ method public String getType();
+ method public CharSequence? getTypeDisplayName();
+ method public boolean isAutoSelectAllowed();
+ property public final android.graphics.drawable.Icon icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence? subtitle;
+ property public final CharSequence title;
+ property public String type;
+ property public final CharSequence? typeDisplayName;
+ }
+
+ public static final class CustomCredentialEntry.Builder {
+ ctor public CustomCredentialEntry.Builder(android.content.Context context, String type, CharSequence title, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetCredentialOption beginGetCredentialOption);
+ method public androidx.credentials.provider.CustomCredentialEntry build();
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setIcon(android.graphics.drawable.Icon icon);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setSubtitle(CharSequence? subtitle);
+ method public androidx.credentials.provider.CustomCredentialEntry.Builder setTypeDisplayName(CharSequence? typeDisplayName);
+ }
+
+ public final class IntentHandlerConverters {
+ method @RequiresApi(34) public static androidx.credentials.provider.BeginGetCredentialResponse? getBeginGetResponse(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.CreateCredentialResponse? getCreateCredentialCredentialResponse(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.CreateCredentialException? getCreateCredentialException(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.GetCredentialException? getGetCredentialException(android.content.Intent);
+ method @RequiresApi(34) public static android.credentials.GetCredentialResponse? getGetCredentialResponse(android.content.Intent);
+ }
+
+ @RequiresApi(26) public final class PasswordCredentialEntry extends androidx.credentials.provider.CredentialEntry {
+ ctor public PasswordCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon icon, optional boolean isAutoSelectAllowed);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ }
+
+ public static final class PasswordCredentialEntry.Builder {
+ ctor public PasswordCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPasswordOption beginGetPasswordOption);
+ method public androidx.credentials.provider.PasswordCredentialEntry build();
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setIcon(android.graphics.drawable.Icon icon);
+ method public androidx.credentials.provider.PasswordCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ @RequiresApi(34) public final class PendingIntentHandler {
+ ctor public PendingIntentHandler();
+ method public static androidx.credentials.provider.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public static androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public static void setBeginGetCredentialResponse(android.content.Intent intent, androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public static void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public static void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public static void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public static void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ field public static final androidx.credentials.provider.PendingIntentHandler.Companion Companion;
+ }
+
+ public static final class PendingIntentHandler.Companion {
+ method public androidx.credentials.provider.BeginGetCredentialRequest? retrieveBeginGetCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderCreateCredentialRequest? retrieveProviderCreateCredentialRequest(android.content.Intent intent);
+ method public androidx.credentials.provider.ProviderGetCredentialRequest? retrieveProviderGetCredentialRequest(android.content.Intent intent);
+ method public void setBeginGetCredentialResponse(android.content.Intent intent, androidx.credentials.provider.BeginGetCredentialResponse response);
+ method public void setCreateCredentialException(android.content.Intent intent, androidx.credentials.exceptions.CreateCredentialException exception);
+ method public void setCreateCredentialResponse(android.content.Intent intent, androidx.credentials.CreateCredentialResponse response);
+ method public void setGetCredentialException(android.content.Intent intent, androidx.credentials.exceptions.GetCredentialException exception);
+ method public void setGetCredentialResponse(android.content.Intent intent, androidx.credentials.GetCredentialResponse response);
+ }
+
+ public final class ProviderClearCredentialStateRequest {
+ ctor public ProviderClearCredentialStateRequest(androidx.credentials.provider.CallingAppInfo callingAppInfo);
+ method public androidx.credentials.provider.CallingAppInfo getCallingAppInfo();
+ property public final androidx.credentials.provider.CallingAppInfo callingAppInfo;
+ }
+
+ public final class ProviderCreateCredentialRequest {
+ ctor public ProviderCreateCredentialRequest(androidx.credentials.CreateCredentialRequest callingRequest, androidx.credentials.provider.CallingAppInfo callingAppInfo);
+ method public androidx.credentials.provider.CallingAppInfo getCallingAppInfo();
+ method public androidx.credentials.CreateCredentialRequest getCallingRequest();
+ property public final androidx.credentials.provider.CallingAppInfo callingAppInfo;
+ property public final androidx.credentials.CreateCredentialRequest callingRequest;
+ }
+
+ public final class ProviderGetCredentialRequest {
+ ctor public ProviderGetCredentialRequest(java.util.List<? extends androidx.credentials.CredentialOption> credentialOptions, androidx.credentials.provider.CallingAppInfo callingAppInfo);
+ method public androidx.credentials.provider.CallingAppInfo getCallingAppInfo();
+ method public java.util.List<androidx.credentials.CredentialOption> getCredentialOptions();
+ property public final androidx.credentials.provider.CallingAppInfo callingAppInfo;
+ property public final java.util.List<androidx.credentials.CredentialOption> credentialOptions;
+ }
+
+ @RequiresApi(26) public final class PublicKeyCredentialEntry extends androidx.credentials.provider.CredentialEntry {
+ ctor public PublicKeyCredentialEntry(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption, optional CharSequence? displayName, optional java.time.Instant? lastUsedTime, optional android.graphics.drawable.Icon icon, optional boolean isAutoSelectAllowed);
+ method public CharSequence? getDisplayName();
+ method public android.graphics.drawable.Icon getIcon();
+ method public java.time.Instant? getLastUsedTime();
+ method public android.app.PendingIntent getPendingIntent();
+ method public CharSequence getTypeDisplayName();
+ method public CharSequence getUsername();
+ method public boolean isAutoSelectAllowed();
+ property public final CharSequence? displayName;
+ property public final android.graphics.drawable.Icon icon;
+ property public final boolean isAutoSelectAllowed;
+ property public final java.time.Instant? lastUsedTime;
+ property public final android.app.PendingIntent pendingIntent;
+ property public final CharSequence typeDisplayName;
+ property public final CharSequence username;
+ }
+
+ public static final class PublicKeyCredentialEntry.Builder {
+ ctor public PublicKeyCredentialEntry.Builder(android.content.Context context, CharSequence username, android.app.PendingIntent pendingIntent, androidx.credentials.provider.BeginGetPublicKeyCredentialOption beginGetPublicKeyCredentialOption);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry build();
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setAutoSelectAllowed(boolean autoSelectAllowed);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setDisplayName(CharSequence? displayName);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setIcon(android.graphics.drawable.Icon icon);
+ method public androidx.credentials.provider.PublicKeyCredentialEntry.Builder setLastUsedTime(java.time.Instant? lastUsedTime);
+ }
+
+ public final class RemoteEntry {
+ ctor public RemoteEntry(android.app.PendingIntent pendingIntent);
+ method public android.app.PendingIntent getPendingIntent();
+ property public final android.app.PendingIntent pendingIntent;
+ }
+
+ public static final class RemoteEntry.Builder {
+ ctor public RemoteEntry.Builder(android.app.PendingIntent pendingIntent);
+ method public androidx.credentials.provider.RemoteEntry build();
+ }
+
+}
+
diff --git a/credentials/credentials/build.gradle b/credentials/credentials/build.gradle
index 76d78db..e869105 100644
--- a/credentials/credentials/build.gradle
+++ b/credentials/credentials/build.gradle
@@ -26,7 +26,6 @@
api("androidx.annotation:annotation:1.5.0")
api(libs.kotlinStdlib)
implementation(libs.kotlinCoroutinesCore)
- api("androidx.core:core:1.11.0-beta02")
samples(project(":credentials:credentials-samples"))
androidTestImplementation("androidx.activity:activity:1.2.0")
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorAssertionResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorAssertionResponse.kt
new file mode 100644
index 0000000..2b326d4
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorAssertionResponse.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import androidx.annotation.RestrictTo
+import java.security.MessageDigest
+import org.json.JSONObject
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class AuthenticatorAssertionResponse(
+ private val requestOptions: PublicKeyCredentialRequestOptions,
+ private val credentialId: ByteArray,
+ private val origin: String,
+ private val up: Boolean,
+ private val uv: Boolean,
+ private val be: Boolean,
+ private val bs: Boolean,
+ private var userHandle: ByteArray,
+ private val packageName: String? = null,
+ private val clientDataHash: ByteArray? = null,
+) : AuthenticatorResponse {
+ override var clientJson = JSONObject()
+ var authenticatorData: ByteArray
+ var signature: ByteArray = byteArrayOf()
+
+ init {
+ clientJson.put("type", "webauthn.get")
+ clientJson.put("challenge", WebAuthnUtils.b64Encode(requestOptions.challenge))
+ clientJson.put("origin", origin)
+ if (packageName != null) {
+ clientJson.put("androidPackageName", packageName)
+ }
+
+ authenticatorData = defaultAuthenticatorData()
+ }
+
+ fun defaultAuthenticatorData(): ByteArray {
+ val md = MessageDigest.getInstance("SHA-256")
+ val rpHash = md.digest(requestOptions.rpId.toByteArray())
+ var flags: Int = 0
+ if (up) {
+ flags = flags or 0x01
+ }
+ if (uv) {
+ flags = flags or 0x04
+ }
+ if (be) {
+ flags = flags or 0x08
+ }
+ if (bs) {
+ flags = flags or 0x10
+ }
+ val ret = rpHash + byteArrayOf(flags.toByte()) + byteArrayOf(0, 0, 0, 0)
+ return ret
+ }
+
+ fun dataToSign(): ByteArray {
+ val md = MessageDigest.getInstance("SHA-256")
+ var hash: ByteArray
+ if (clientDataHash != null) {
+ hash = clientDataHash
+ } else {
+ hash = md.digest(clientJson.toString().toByteArray())
+ }
+
+ return authenticatorData + hash
+ }
+
+ override fun json(): JSONObject {
+ val clientData = clientJson.toString().toByteArray()
+ val response = JSONObject()
+ if (clientDataHash == null) {
+ response.put("clientDataJSON", WebAuthnUtils.b64Encode(clientData))
+ }
+ response.put("authenticatorData", WebAuthnUtils.b64Encode(authenticatorData))
+ response.put("signature", WebAuthnUtils.b64Encode(signature))
+ response.put("userHandle", WebAuthnUtils.b64Encode(userHandle))
+ return response
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorAttestationResponse.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorAttestationResponse.kt
new file mode 100644
index 0000000..61a08f3
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorAttestationResponse.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import androidx.annotation.RestrictTo
+import java.security.MessageDigest
+import org.json.JSONArray
+import org.json.JSONObject
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class AuthenticatorAttestationResponse(
+ private val requestOptions: PublicKeyCredentialCreationOptions,
+ private val credentialId: ByteArray,
+ private val credentialPublicKey: ByteArray,
+ private val origin: String,
+ private val up: Boolean,
+ private val uv: Boolean,
+ private val be: Boolean,
+ private val bs: Boolean,
+ private val packageName: String? = null,
+ private val clientDataHash: ByteArray? = null,
+) : AuthenticatorResponse {
+ override var clientJson = JSONObject()
+ var attestationObject: ByteArray
+
+ init {
+ clientJson.put("type", "webauthn.create")
+ clientJson.put("challenge", WebAuthnUtils.b64Encode(requestOptions.challenge))
+ clientJson.put("origin", origin)
+ if (packageName != null) {
+ clientJson.put("androidPackageName", packageName)
+ }
+
+ attestationObject = defaultAttestationObject()
+ }
+
+ private fun authData(): ByteArray {
+ val md = MessageDigest.getInstance("SHA-256")
+ val rpHash = md.digest(requestOptions.rp.id.toByteArray())
+ var flags: Int = 0
+ if (up) {
+ flags = flags or 0x01
+ }
+ if (uv) {
+ flags = flags or 0x04
+ }
+ if (be) {
+ flags = flags or 0x08
+ }
+ if (bs) {
+ flags = flags or 0x10
+ }
+ flags = flags or 0x40
+
+ val aaguid = ByteArray(16) { 0 }
+ val credIdLen = byteArrayOf((credentialId.size shr 8).toByte(), credentialId.size.toByte())
+
+ val ret =
+ rpHash +
+ byteArrayOf(flags.toByte()) +
+ byteArrayOf(0, 0, 0, 0) +
+ aaguid +
+ credIdLen +
+ credentialId +
+ credentialPublicKey
+
+ return ret
+ }
+
+ private fun defaultAttestationObject(): ByteArray {
+ val ao = mutableMapOf<String, Any>()
+ ao.put("fmt", "none")
+ ao.put("attStmt", emptyMap<Any, Any>())
+ ao.put("authData", authData())
+ return Cbor().encode(ao)
+ }
+
+ override fun json(): JSONObject {
+ // See AuthenticatorAttestationResponseJSON at
+ // https://w3c.github.io/webauthn/#ref-for-dom-publickeycredential-tojson
+
+ val clientData = clientJson.toString().toByteArray()
+ val response = JSONObject()
+ if (clientDataHash == null) {
+ response.put("clientDataJSON", WebAuthnUtils.b64Encode(clientData))
+ }
+ response.put("attestationObject", WebAuthnUtils.b64Encode(attestationObject))
+ response.put("transports", JSONArray(listOf("internal", "hybrid")))
+
+ return response
+ }
+}
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorResponse.kt
similarity index 63%
copy from core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
copy to credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorResponse.kt
index 9914490..6ac823d 100644
--- a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/AuthenticatorResponse.kt
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-package androidx.core.performance
+package androidx.credentials.webauthn
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
+import androidx.annotation.RestrictTo
+import org.json.JSONObject
-/** Unit tests for [DevicePerformance]. */
-class DevicePerformanceTest {
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+interface AuthenticatorResponse {
+ var clientJson: JSONObject
- @Test
- fun mediaPerformanceClass() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
+ fun json(): JSONObject
}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/Cbor.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/Cbor.kt
new file mode 100644
index 0000000..4c6ae0d
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/Cbor.kt
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import androidx.annotation.RestrictTo
+import java.lang.IllegalArgumentException
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class Cbor {
+ data class Item(val item: Any, val len: Int)
+
+ data class Arg(val arg: Long, val len: Int)
+
+ val TYPE_UNSIGNED_INT = 0x00
+ val TYPE_NEGATIVE_INT = 0x01
+ val TYPE_BYTE_STRING = 0x02
+ val TYPE_TEXT_STRING = 0x03
+ val TYPE_ARRAY = 0x04
+ val TYPE_MAP = 0x05
+ val TYPE_TAG = 0x06
+ val TYPE_FLOAT = 0x07
+
+ fun decode(data: ByteArray): Any {
+ val ret = parseItem(data, 0)
+ return ret.item
+ }
+
+ fun encode(data: Any): ByteArray {
+ if (data is Number) {
+ if (data is Double) {
+ throw IllegalArgumentException("Don't support doubles yet")
+ } else {
+ val value = data.toLong()
+ if (value >= 0) {
+ return createArg(TYPE_UNSIGNED_INT, value)
+ } else {
+ return createArg(TYPE_NEGATIVE_INT, -1 - value)
+ }
+ }
+ }
+ if (data is ByteArray) {
+ return createArg(TYPE_BYTE_STRING, data.size.toLong()) + data
+ }
+ if (data is String) {
+ return createArg(TYPE_TEXT_STRING, data.length.toLong()) + data.encodeToByteArray()
+ }
+ if (data is List<*>) {
+ var ret = createArg(TYPE_ARRAY, data.size.toLong())
+ for (i in data) {
+ ret += encode(i!!)
+ }
+ return ret
+ }
+ if (data is Map<*, *>) {
+ // See:
+ // https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#ctap2-canonical-cbor-encoding-form
+ var ret = createArg(TYPE_MAP, data.size.toLong())
+ var byteMap: MutableMap<ByteArray, ByteArray> = mutableMapOf()
+ for (i in data) {
+ // Convert to byte arrays so we can sort them.
+ byteMap.put(encode(i.key!!), encode(i.value!!))
+ }
+
+ var keysList = ArrayList<ByteArray>(byteMap.keys)
+ keysList.sortedWith(Comparator<ByteArray> { a, b ->
+ // If two keys have different lengths, the shorter one sorts earlier;
+ // If two keys have the same length, the one with the lower value in (byte-wise)
+ // lexical order sorts earlier.
+ var aBytes = byteMap.get(a)!!
+ var bBytes = byteMap.get(b)!!
+ when {
+ a.size > b.size -> 1
+ a.size < b.size -> -1
+ aBytes.size > bBytes.size -> 1
+ aBytes.size < bBytes.size -> -1
+ else -> 0
+ }
+ })
+
+ for (key in keysList) {
+ ret += key
+ ret += byteMap.get(key)!!
+ }
+ return ret
+ }
+ throw IllegalArgumentException("Bad type")
+ }
+
+ private fun getType(data: ByteArray, offset: Int): Int {
+ val d = data[offset].toInt()
+ return (d and 0xFF) shr 5
+ }
+
+ private fun getArg(data: ByteArray, offset: Int): Arg {
+ val arg = data[offset].toLong() and 0x1F
+ if (arg < 24) {
+ return Arg(arg, 1)
+ }
+ if (arg == 24L) {
+ return Arg(data[offset + 1].toLong() and 0xFF, 2)
+ }
+ if (arg == 25L) {
+ var ret = (data[offset + 1].toLong() and 0xFF) shl 8
+ ret = ret or (data[offset + 2].toLong() and 0xFF)
+ return Arg(ret, 3)
+ }
+ if (arg == 26L) {
+ var ret = (data[offset + 1].toLong() and 0xFF) shl 24
+ ret = ret or ((data[offset + 2].toLong() and 0xFF) shl 16)
+ ret = ret or ((data[offset + 3].toLong() and 0xFF) shl 8)
+ ret = ret or (data[offset + 4].toLong() and 0xFF)
+ return Arg(ret, 5)
+ }
+ throw IllegalArgumentException("Bad arg")
+ }
+
+ private fun parseItem(data: ByteArray, offset: Int): Item {
+ val itemType = getType(data, offset)
+ val arg = getArg(data, offset)
+ println("Type $itemType ${arg.arg} ${arg.len}")
+
+ when (itemType) {
+ TYPE_UNSIGNED_INT -> {
+ return Item(arg.arg, arg.len)
+ }
+ TYPE_NEGATIVE_INT -> {
+ return Item(-1 - arg.arg, arg.len)
+ }
+ TYPE_BYTE_STRING -> {
+ val ret =
+ data.sliceArray(offset + arg.len.toInt() until offset + arg.len.toInt() + arg.arg.toInt())
+ return Item(ret, arg.len + arg.arg.toInt())
+ }
+ TYPE_TEXT_STRING -> {
+ val ret =
+ data.sliceArray(offset + arg.len.toInt() until offset + arg.len.toInt() + arg.arg.toInt())
+ return Item(ret.toString(Charsets.UTF_8), arg.len + arg.arg.toInt())
+ }
+ TYPE_ARRAY -> {
+ val ret = mutableListOf<Any>()
+ var consumed = arg.len
+ for (i in 0 until arg.arg.toInt()) {
+ val item = parseItem(data, offset + consumed)
+ ret.add(item.item)
+ consumed += item.len
+ }
+ return Item(ret.toList(), consumed)
+ }
+ TYPE_MAP -> {
+ val ret = mutableMapOf<Any, Any>()
+ var consumed = arg.len
+ for (i in 0 until arg.arg.toInt()) {
+ val key = parseItem(data, offset + consumed)
+ consumed += key.len
+ val value = parseItem(data, offset + consumed)
+ consumed += value.len
+ ret[key.item] = value.item
+ }
+ return Item(ret.toMap(), consumed)
+ }
+ else -> {
+ throw IllegalArgumentException("Bad type")
+ }
+ }
+ }
+
+ private fun createArg(type: Int, arg: Long): ByteArray {
+ val t = type shl 5
+ val a = arg.toInt()
+ if (arg < 24) {
+ return byteArrayOf(((t or a) and 0xFF).toByte())
+ }
+ if (arg <= 0xFF) {
+ return byteArrayOf(((t or 24) and 0xFF).toByte(), (a and 0xFF).toByte())
+ }
+ if (arg <= 0xFFFF) {
+ return byteArrayOf(
+ ((t or 25) and 0xFF).toByte(),
+ ((a shr 8) and 0xFF).toByte(),
+ (a and 0xFF).toByte()
+ )
+ }
+ if (arg <= 0xFFFFFFFF) {
+ return byteArrayOf(
+ ((t or 26) and 0xFF).toByte(),
+ ((a shr 24) and 0xFF).toByte(),
+ ((a shr 16) and 0xFF).toByte(),
+ ((a shr 8) and 0xFF).toByte(),
+ (a and 0xFF).toByte()
+ )
+ }
+ throw IllegalArgumentException("bad Arg")
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/FidoDataTypes.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/FidoDataTypes.kt
new file mode 100644
index 0000000..c9d4538
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/FidoDataTypes.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import androidx.annotation.RestrictTo
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+data class PublicKeyCredentialRpEntity(val name: String, val id: String)
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+data class PublicKeyCredentialUserEntity(
+ val name: String,
+ val id: ByteArray,
+ val displayName: String
+)
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+data class PublicKeyCredentialParameters(val type: String, val alg: Long)
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+data class PublicKeyCredentialDescriptor(
+ val type: String,
+ val id: ByteArray,
+ val transports: List<String>
+)
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+data class AuthenticatorSelectionCriteria(
+ val authenticatorAttachment: String,
+ val residentKey: String,
+ val requireResidentKey: Boolean = false,
+ val userVerification: String = "preferred"
+)
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/FidoPublicKeyCredential.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/FidoPublicKeyCredential.kt
new file mode 100644
index 0000000..d271e44
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/FidoPublicKeyCredential.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import androidx.annotation.RestrictTo
+import org.json.JSONObject
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class FidoPublicKeyCredential(
+ val rawId: ByteArray,
+ val response: AuthenticatorResponse,
+ val authenticatorAttachment: String
+) {
+
+ fun json(): String {
+ // See RegistrationResponseJSON at
+ // https://w3c.github.io/webauthn/#ref-for-dom-publickeycredential-tojson
+ val encodedId = WebAuthnUtils.b64Encode(rawId)
+ val ret = JSONObject()
+ ret.put("id", encodedId)
+ ret.put("rawId", encodedId)
+ ret.put("type", "public-key")
+ ret.put("authenticatorAttachment", authenticatorAttachment)
+ ret.put("response", response.json())
+ ret.put("clientExtensionResults", JSONObject())
+
+ return ret.toString()
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/PublicKeyCredentialCreationOptions.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/PublicKeyCredentialCreationOptions.kt
new file mode 100644
index 0000000..2a2140c
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/PublicKeyCredentialCreationOptions.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import android.util.Log
+import androidx.annotation.RestrictTo
+import org.json.JSONObject
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class PublicKeyCredentialCreationOptions(requestJson: String) {
+ val json: JSONObject
+
+ val rp: PublicKeyCredentialRpEntity
+ val user: PublicKeyCredentialUserEntity
+ val challenge: ByteArray
+ val pubKeyCredParams: List<PublicKeyCredentialParameters>
+
+ var timeout: Long
+ var excludeCredentials: List<PublicKeyCredentialDescriptor>
+ var authenticatorSelection: AuthenticatorSelectionCriteria
+ var attestation: String
+
+ init {
+ json = JSONObject(requestJson)
+ val challengeString = json.getString("challenge")
+ challenge = WebAuthnUtils.b64Decode(challengeString)
+ val rpJson = json.getJSONObject("rp")
+ rp = PublicKeyCredentialRpEntity(rpJson.getString("name"), rpJson.getString("id"))
+ val rpUser = json.getJSONObject("user")
+ val userId = WebAuthnUtils.b64Decode(rpUser.getString("id"))
+ user =
+ PublicKeyCredentialUserEntity(
+ rpUser.getString("name"),
+ userId,
+ rpUser.getString("displayName")
+ )
+ val pubKeyCredParamsJson = json.getJSONArray("pubKeyCredParams")
+ val pubKeyCredParamsTmp: MutableList<PublicKeyCredentialParameters> = mutableListOf()
+ for (i in 0 until pubKeyCredParamsJson.length()) {
+ val e = pubKeyCredParamsJson.getJSONObject(i)
+ pubKeyCredParamsTmp.add(PublicKeyCredentialParameters(e.getString("type"), e.getLong("alg")))
+ }
+ pubKeyCredParams = pubKeyCredParamsTmp.toList()
+
+ timeout = json.optLong("timeout", 0)
+ // TODO: Fix excludeCredentials and authenticatorSelection
+ excludeCredentials = emptyList()
+ authenticatorSelection = AuthenticatorSelectionCriteria("platform", "required")
+ attestation = json.optString("attestation", "none")
+
+ Log.i("WebAuthn", "Challenge $challenge()")
+ Log.i("WebAuthn", "rp $rp")
+ Log.i("WebAuthn", "user $user")
+ Log.i("WebAuthn", "pubKeyCredParams $pubKeyCredParams")
+ Log.i("WebAuthn", "timeout $timeout")
+ Log.i("WebAuthn", "excludeCredentials $excludeCredentials")
+ Log.i("WebAuthn", "authenticatorSelection $authenticatorSelection")
+ Log.i("WebAuthn", "attestation $attestation")
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/PublicKeyCredentialRequestOptions.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/PublicKeyCredentialRequestOptions.kt
new file mode 100644
index 0000000..6950701
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/PublicKeyCredentialRequestOptions.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import androidx.annotation.RestrictTo
+import org.json.JSONObject
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class PublicKeyCredentialRequestOptions(requestJson: String) {
+ val json: JSONObject
+
+ val challenge: ByteArray
+ val timeout: Long
+ val rpId: String
+ val userVerification: String
+
+ init {
+ json = JSONObject(requestJson)
+
+ val challengeString = json.getString("challenge")
+ challenge = WebAuthnUtils.b64Decode(challengeString)
+ timeout = json.optLong("timeout", 0)
+ rpId = json.optString("rpId", "")
+ userVerification = json.optString("userVerification", "preferred")
+ }
+}
diff --git a/credentials/credentials/src/main/java/androidx/credentials/webauthn/Util.kt b/credentials/credentials/src/main/java/androidx/credentials/webauthn/Util.kt
new file mode 100644
index 0000000..f247a9c
--- /dev/null
+++ b/credentials/credentials/src/main/java/androidx/credentials/webauthn/Util.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.credentials.webauthn
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.util.Base64
+import androidx.annotation.RestrictTo
+import androidx.credentials.provider.CallingAppInfo
+import java.security.MessageDigest
+
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+internal class WebAuthnUtils {
+ companion object {
+ fun b64Decode(str: String): ByteArray {
+ return Base64.decode(str, Base64.NO_PADDING or Base64.NO_WRAP or Base64.URL_SAFE)
+ }
+
+ fun b64Encode(data: ByteArray): String {
+ return Base64.encodeToString(data, Base64.NO_PADDING or Base64.NO_WRAP or Base64.URL_SAFE)
+ }
+
+ @SuppressLint("ClassVerificationFailure")
+ fun appInfoToOrigin(info: CallingAppInfo): String {
+ if (Build.VERSION.SDK_INT >= 28) {
+ val cert = info.signingInfo.apkContentsSigners[0].toByteArray()
+ val md = MessageDigest.getInstance("SHA-256")
+ val certHash = md.digest(cert)
+ return "android:apk-key-hash:${b64Encode(certHash)}"
+ }
+ return ""
+ }
+ }
+}
diff --git a/datastore/datastore-core/lint-baseline.xml b/datastore/datastore-core/lint-baseline.xml
deleted file mode 100644
index b8e7866..0000000
--- a/datastore/datastore-core/lint-baseline.xml
+++ /dev/null
@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-beta05" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0-beta05)" variant="all" version="8.1.0-beta05">
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" coordinator.lock {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" version = coordinator.getVersion()"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" coordinator.updateNotifications.conflate().collect {"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `readDataAndUpdateCache` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" readDataAndUpdateCache(requireLock = true)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" coordinator.lock { block() }"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `readDataFromFileOrDefault` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" val data = readDataFromFileOrDefault()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" Data(data, data.hashCode(), version = coordinator.getVersion())"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" val preLockVersion = coordinator.getVersion()"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" coordinator.tryLock { locked ->"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `readDataFromFileOrDefault` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" val data = readDataFromFileOrDefault()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" val version = if (locked) coordinator.getVersion() else preLockVersion"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `readDataFromFileOrDefault` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" newData = readDataFromFileOrDefault()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getCoordinator` of class `DataStoreImpl` requires synthetic accessor"
- errorLine1=" version = coordinator.getVersion()"
- errorLine2=" ~~~~~~~~~~~">
- <location
- file="src/commonMain/kotlin/androidx/datastore/core/DataStoreImpl.kt"/>
- </issue>
-
-</issues>
diff --git a/development/plot-benchmarks/package-lock.json b/development/plot-benchmarks/package-lock.json
index 5ee7330..451e5aa 100644
--- a/development/plot-benchmarks/package-lock.json
+++ b/development/plot-benchmarks/package-lock.json
@@ -8,16 +8,17 @@
"name": "plot-benchmarks",
"version": "0.1.0",
"dependencies": {
- "chart.js": "^4.3.0"
+ "chart.js": "^4.3.1",
+ "comlink": "4.4.1"
},
"devDependencies": {
- "@sveltejs/vite-plugin-svelte": "^2.4.1",
- "@tsconfig/svelte": "^4.0.1",
- "svelte": "^4.0.0",
- "svelte-check": "^3.4.3",
- "tslib": "^2.5.0",
- "typescript": "^5.0.0",
- "vite": "^4.3.9"
+ "@sveltejs/vite-plugin-svelte": "^2.4.3",
+ "@tsconfig/svelte": "^5.0.0",
+ "svelte": "^4.1.1",
+ "svelte-check": "^3.4.6",
+ "tslib": "^2.6.1",
+ "typescript": "^5.1.6",
+ "vite": "^4.4.7"
}
},
"node_modules/@ampproject/remapping": {
@@ -34,9 +35,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
- "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.16.tgz",
+ "integrity": "sha512-gCHjjQmA8L0soklKbLKA6pgsLk1byULuHe94lkZDzcO3/Ta+bbeewJioEn1Fr7kgy9NWNFy/C+MrBwC6I/WCug==",
"cpu": [
"arm"
],
@@ -50,9 +51,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
- "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.16.tgz",
+ "integrity": "sha512-wsCqSPqLz+6Ov+OM4EthU43DyYVVyfn15S4j1bJzylDpc1r1jZFFfJQNfDuT8SlgwuqpmpJXK4uPlHGw6ve7eA==",
"cpu": [
"arm64"
],
@@ -66,9 +67,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
- "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.16.tgz",
+ "integrity": "sha512-ldsTXolyA3eTQ1//4DS+E15xl0H/3DTRJaRL0/0PgkqDsI0fV/FlOtD+h0u/AUJr+eOTlZv4aC9gvfppo3C4sw==",
"cpu": [
"x64"
],
@@ -82,9 +83,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
- "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.16.tgz",
+ "integrity": "sha512-aBxruWCII+OtluORR/KvisEw0ALuw/qDQWvkoosA+c/ngC/Kwk0lLaZ+B++LLS481/VdydB2u6tYpWxUfnLAIw==",
"cpu": [
"arm64"
],
@@ -98,9 +99,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
- "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.16.tgz",
+ "integrity": "sha512-6w4Dbue280+rp3LnkgmriS1icOUZDyPuZo/9VsuMUTns7SYEiOaJ7Ca1cbhu9KVObAWfmdjUl4gwy9TIgiO5eA==",
"cpu": [
"x64"
],
@@ -114,9 +115,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
- "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.16.tgz",
+ "integrity": "sha512-x35fCebhe9s979DGKbVAwXUOcTmCIE32AIqB9CB1GralMIvxdnMLAw5CnID17ipEw9/3MvDsusj/cspYt2ZLNQ==",
"cpu": [
"arm64"
],
@@ -130,9 +131,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
- "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.16.tgz",
+ "integrity": "sha512-YM98f+PeNXF3GbxIJlUsj+McUWG1irguBHkszCIwfr3BXtXZsXo0vqybjUDFfu9a8Wr7uUD/YSmHib+EeGAFlg==",
"cpu": [
"x64"
],
@@ -146,9 +147,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
- "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.16.tgz",
+ "integrity": "sha512-b5ABb+5Ha2C9JkeZXV+b+OruR1tJ33ePmv9ZwMeETSEKlmu/WJ45XTTG+l6a2KDsQtJJ66qo/hbSGBtk0XVLHw==",
"cpu": [
"arm"
],
@@ -162,9 +163,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
- "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.16.tgz",
+ "integrity": "sha512-XIqhNUxJiuy+zsR77+H5Z2f7s4YRlriSJKtvx99nJuG5ATuJPjmZ9n0ANgnGlPCpXGSReFpgcJ7O3SMtzIFeiQ==",
"cpu": [
"arm64"
],
@@ -178,9 +179,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
- "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.16.tgz",
+ "integrity": "sha512-no+pfEpwnRvIyH+txbBAWtjxPU9grslmTBfsmDndj7bnBmr55rOo/PfQmRfz7Qg9isswt1FP5hBbWb23fRWnow==",
"cpu": [
"ia32"
],
@@ -194,9 +195,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
- "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.16.tgz",
+ "integrity": "sha512-Zbnczs9ZXjmo0oZSS0zbNlJbcwKXa/fcNhYQjahDs4Xg18UumpXG/lwM2lcSvHS3mTrRyCYZvJbmzYc4laRI1g==",
"cpu": [
"loong64"
],
@@ -210,9 +211,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
- "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.16.tgz",
+ "integrity": "sha512-YMF7hih1HVR/hQVa/ot4UVffc5ZlrzEb3k2ip0nZr1w6fnYypll9td2qcoMLvd3o8j3y6EbJM3MyIcXIVzXvQQ==",
"cpu": [
"mips64el"
],
@@ -226,9 +227,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
- "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.16.tgz",
+ "integrity": "sha512-Wkz++LZ29lDwUyTSEnzDaaP5OveOgTU69q9IyIw9WqLRxM4BjTBjz9un4G6TOvehWpf/J3gYVFN96TjGHrbcNQ==",
"cpu": [
"ppc64"
],
@@ -242,9 +243,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
- "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.16.tgz",
+ "integrity": "sha512-LFMKZ30tk78/mUv1ygvIP+568bwf4oN6reG/uczXnz6SvFn4e2QUFpUpZY9iSJT6Qpgstrhef/nMykIXZtZWGQ==",
"cpu": [
"riscv64"
],
@@ -258,9 +259,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
- "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.16.tgz",
+ "integrity": "sha512-3ZC0BgyYHYKfZo3AV2/66TD/I9tlSBaW7eWTEIkrQQKfJIifKMMttXl9FrAg+UT0SGYsCRLI35Gwdmm96vlOjg==",
"cpu": [
"s390x"
],
@@ -274,9 +275,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
- "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.16.tgz",
+ "integrity": "sha512-xu86B3647DihHJHv/wx3NCz2Dg1gjQ8bbf9cVYZzWKY+gsvxYmn/lnVlqDRazObc3UMwoHpUhNYaZset4X8IPA==",
"cpu": [
"x64"
],
@@ -290,9 +291,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
- "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.16.tgz",
+ "integrity": "sha512-uVAgpimx9Ffw3xowtg/7qQPwHFx94yCje+DoBx+LNm2ePDpQXHrzE+Sb0Si2VBObYz+LcRps15cq+95YM7gkUw==",
"cpu": [
"x64"
],
@@ -306,9 +307,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
- "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.16.tgz",
+ "integrity": "sha512-6OjCQM9wf7z8/MBi6BOWaTL2AS/SZudsZtBziXMtNI8r/U41AxS9x7jn0ATOwVy08OotwkPqGRMkpPR2wcTJXA==",
"cpu": [
"x64"
],
@@ -322,9 +323,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
- "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.16.tgz",
+ "integrity": "sha512-ZoNkruFYJp9d1LbUYCh8awgQDvB9uOMZqlQ+gGEZR7v6C+N6u7vPr86c+Chih8niBR81Q/bHOSKGBK3brJyvkQ==",
"cpu": [
"x64"
],
@@ -338,9 +339,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
- "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.16.tgz",
+ "integrity": "sha512-+j4anzQ9hrs+iqO+/wa8UE6TVkKua1pXUb0XWFOx0FiAj6R9INJ+WE//1/Xo6FG1vB5EpH3ko+XcgwiDXTxcdw==",
"cpu": [
"arm64"
],
@@ -354,9 +355,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
- "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.16.tgz",
+ "integrity": "sha512-5PFPmq3sSKTp9cT9dzvI67WNfRZGvEVctcZa1KGjDDu4n3H8k59Inbk0du1fz0KrAbKKNpJbdFXQMDUz7BG4rQ==",
"cpu": [
"ia32"
],
@@ -370,9 +371,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
- "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.16.tgz",
+ "integrity": "sha512-sCIVrrtcWN5Ua7jYXNG1xD199IalrbfV2+0k/2Zf2OyV2FtnQnMgdzgpRAbi4AWlKJj1jkX+M+fEGPQj6BQB4w==",
"cpu": [
"x64"
],
@@ -480,31 +481,31 @@
}
},
"node_modules/@sveltejs/vite-plugin-svelte": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.1.tgz",
- "integrity": "sha512-bNNKvoRY89ptY7udeBSCmTdCVwkjmMcZ0j/z9J5MuedT8jPjq0zrknAo/jF1sToAza4NVaAgR9AkZoD9oJJmnA==",
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.3.tgz",
+ "integrity": "sha512-NY2h+B54KHZO3kDURTdARqthn6D4YSIebtfW75NvZ/fwyk4G+AJw3V/i0OBjyN4406Ht9yZcnNWMuRUFnDNNiA==",
"dev": true,
"dependencies": {
- "@sveltejs/vite-plugin-svelte-inspector": "^1.0.2",
+ "@sveltejs/vite-plugin-svelte-inspector": "^1.0.3",
"debug": "^4.3.4",
"deepmerge": "^4.3.1",
"kleur": "^4.1.5",
- "magic-string": "^0.30.0",
- "svelte-hmr": "^0.15.1",
+ "magic-string": "^0.30.1",
+ "svelte-hmr": "^0.15.2",
"vitefu": "^0.2.4"
},
"engines": {
"node": "^14.18.0 || >= 16"
},
"peerDependencies": {
- "svelte": "^3.54.0 || ^4.0.0-next.0",
+ "svelte": "^3.54.0 || ^4.0.0",
"vite": "^4.0.0"
}
},
"node_modules/@sveltejs/vite-plugin-svelte-inspector": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.2.tgz",
- "integrity": "sha512-Cy1dUMcYCnDVV/hPLXa43YZJ2jGKVW5rA0xuNL9dlmYhT0yoS1g7+FOFSRlgk0BXKk/Oc7grs+8BVA5Iz2fr8A==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.3.tgz",
+ "integrity": "sha512-Khdl5jmmPN6SUsVuqSXatKpQTMIifoQPDanaxC84m9JxIibWvSABJyHpyys0Z+1yYrxY5TTEQm+6elh0XCMaOA==",
"dev": true,
"dependencies": {
"debug": "^4.3.4"
@@ -514,14 +515,14 @@
},
"peerDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.2.0",
- "svelte": "^3.54.0 || ^4.0.0-next.0",
+ "svelte": "^3.54.0 || ^4.0.0",
"vite": "^4.0.0"
}
},
"node_modules/@tsconfig/svelte": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-4.0.1.tgz",
- "integrity": "sha512-B+XlGpmuAQzJqDoBATNCvEPqQg0HkO7S8pM14QDI5NsmtymzRexQ1N+nX2H6RTtFbuFgaZD4I8AAi8voGg0GLg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.0.tgz",
+ "integrity": "sha512-iu5BqFjU0+OcLTNQp7fHe6Bf6zdNeJ9IZjLZMqWLuGzVFm/xx+lm//Tf6koPyRmxo55/Snm6RRQ990n89cRKFw==",
"dev": true
},
"node_modules/@types/estree": {
@@ -562,9 +563,9 @@
}
},
"node_modules/aria-query": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.2.1.tgz",
- "integrity": "sha512-7uFg4b+lETFgdaJyETnILsXgnnzVnkHcgRbwbPwevm5x/LmUlt3MjczMRe1zg824iBgXZNRPTBftNYyRSKLp2g==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"dependencies": {
"dequal": "^2.0.3"
@@ -635,9 +636,9 @@
}
},
"node_modules/chart.js": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.0.tgz",
- "integrity": "sha512-ynG0E79xGfMaV2xAHdbhwiPLczxnNNnasrmPEXriXsPJGjmhOBYzFVEsB65w2qMDz+CaBJJuJD0inE/ab/h36g==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.1.tgz",
+ "integrity": "sha512-QHuISG3hTJ0ftq0I0f5jqH9mNVO9bqG8P+zvMOVslgKajQVvFEX7QAhYNJ+QEmw+uYTwo8XpTimaB82oeTWjxw==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
@@ -685,6 +686,11 @@
"periscopic": "^3.1.0"
}
},
+ "node_modules/comlink": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.1.tgz",
+ "integrity": "sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q=="
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -755,9 +761,9 @@
"dev": true
},
"node_modules/esbuild": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
- "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.16.tgz",
+ "integrity": "sha512-1xLsOXrDqwdHxyXb/x/SOyg59jpf/SH7YMvU5RNSU7z3TInaASNJWNFJ6iRvLvLETZMasF3d1DdZLg7sgRimRQ==",
"dev": true,
"hasInstallScript": true,
"bin": {
@@ -767,28 +773,28 @@
"node": ">=12"
},
"optionalDependencies": {
- "@esbuild/android-arm": "0.17.19",
- "@esbuild/android-arm64": "0.17.19",
- "@esbuild/android-x64": "0.17.19",
- "@esbuild/darwin-arm64": "0.17.19",
- "@esbuild/darwin-x64": "0.17.19",
- "@esbuild/freebsd-arm64": "0.17.19",
- "@esbuild/freebsd-x64": "0.17.19",
- "@esbuild/linux-arm": "0.17.19",
- "@esbuild/linux-arm64": "0.17.19",
- "@esbuild/linux-ia32": "0.17.19",
- "@esbuild/linux-loong64": "0.17.19",
- "@esbuild/linux-mips64el": "0.17.19",
- "@esbuild/linux-ppc64": "0.17.19",
- "@esbuild/linux-riscv64": "0.17.19",
- "@esbuild/linux-s390x": "0.17.19",
- "@esbuild/linux-x64": "0.17.19",
- "@esbuild/netbsd-x64": "0.17.19",
- "@esbuild/openbsd-x64": "0.17.19",
- "@esbuild/sunos-x64": "0.17.19",
- "@esbuild/win32-arm64": "0.17.19",
- "@esbuild/win32-ia32": "0.17.19",
- "@esbuild/win32-x64": "0.17.19"
+ "@esbuild/android-arm": "0.18.16",
+ "@esbuild/android-arm64": "0.18.16",
+ "@esbuild/android-x64": "0.18.16",
+ "@esbuild/darwin-arm64": "0.18.16",
+ "@esbuild/darwin-x64": "0.18.16",
+ "@esbuild/freebsd-arm64": "0.18.16",
+ "@esbuild/freebsd-x64": "0.18.16",
+ "@esbuild/linux-arm": "0.18.16",
+ "@esbuild/linux-arm64": "0.18.16",
+ "@esbuild/linux-ia32": "0.18.16",
+ "@esbuild/linux-loong64": "0.18.16",
+ "@esbuild/linux-mips64el": "0.18.16",
+ "@esbuild/linux-ppc64": "0.18.16",
+ "@esbuild/linux-riscv64": "0.18.16",
+ "@esbuild/linux-s390x": "0.18.16",
+ "@esbuild/linux-x64": "0.18.16",
+ "@esbuild/netbsd-x64": "0.18.16",
+ "@esbuild/openbsd-x64": "0.18.16",
+ "@esbuild/sunos-x64": "0.18.16",
+ "@esbuild/win32-arm64": "0.18.16",
+ "@esbuild/win32-ia32": "0.18.16",
+ "@esbuild/win32-x64": "0.18.16"
}
},
"node_modules/estree-walker": {
@@ -994,12 +1000,12 @@
"dev": true
},
"node_modules/magic-string": {
- "version": "0.30.0",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
- "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==",
+ "version": "0.30.1",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
+ "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==",
"dev": true,
"dependencies": {
- "@jridgewell/sourcemap-codec": "^1.4.13"
+ "@jridgewell/sourcemap-codec": "^1.4.15"
},
"engines": {
"node": ">=12"
@@ -1177,9 +1183,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.24",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
- "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
+ "version": "8.4.27",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
+ "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"dev": true,
"funding": [
{
@@ -1268,9 +1274,9 @@
}
},
"node_modules/rollup": {
- "version": "3.25.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz",
- "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==",
+ "version": "3.26.3",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.3.tgz",
+ "integrity": "sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -1367,16 +1373,16 @@
}
},
"node_modules/svelte": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.0.0.tgz",
- "integrity": "sha512-+yCYu3AEUu9n91dnQNGIbnVp8EmNQtuF/YImW4+FTXRHard7NMo+yTsWzggPAbj3fUEJ1FBJLkql/jkp6YB5pg==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.1.1.tgz",
+ "integrity": "sha512-Enick5fPFISLoVy0MFK45cG+YlQt6upw8skEK9zzTpJnH1DqEv8xOZwizCGSo3Q6HZ7KrZTM0J18poF7aQg5zw==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@jridgewell/trace-mapping": "^0.3.18",
- "acorn": "^8.8.2",
- "aria-query": "^5.2.1",
+ "acorn": "^8.9.0",
+ "aria-query": "^5.3.0",
"axobject-query": "^3.2.1",
"code-red": "^1.0.3",
"css-tree": "^2.3.1",
@@ -1391,9 +1397,9 @@
}
},
"node_modules/svelte-check": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.4.3.tgz",
- "integrity": "sha512-O07soQFY3X0VDt+bcGc6D5naz0cLtjwnmNP9JsEBPVyMemFEqUhL2OdLqvkl5H/u8Jwm50EiAU4BPRn5iin/kg==",
+ "version": "3.4.6",
+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.4.6.tgz",
+ "integrity": "sha512-OBlY8866Zh1zHQTkBMPS6psPi7o2umTUyj6JWm4SacnIHXpWFm658pG32m3dKvKFL49V4ntAkfFHKo4ztH07og==",
"dev": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.17",
@@ -1402,7 +1408,7 @@
"import-fresh": "^3.2.1",
"picocolors": "^1.0.0",
"sade": "^1.7.4",
- "svelte-preprocess": "^5.0.3",
+ "svelte-preprocess": "^5.0.4",
"typescript": "^5.0.3"
},
"bin": {
@@ -1511,15 +1517,15 @@
}
},
"node_modules/tslib": {
- "version": "2.5.3",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
- "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==",
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
+ "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==",
"dev": true
},
"node_modules/typescript": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
- "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
+ "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -1530,14 +1536,14 @@
}
},
"node_modules/vite": {
- "version": "4.3.9",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
- "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
+ "version": "4.4.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz",
+ "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==",
"dev": true,
"dependencies": {
- "esbuild": "^0.17.5",
- "postcss": "^8.4.23",
- "rollup": "^3.21.0"
+ "esbuild": "^0.18.10",
+ "postcss": "^8.4.26",
+ "rollup": "^3.25.2"
},
"bin": {
"vite": "bin/vite.js"
@@ -1545,12 +1551,16 @@
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
+ "lightningcss": "^1.21.0",
"sass": "*",
"stylus": "*",
"sugarss": "*",
@@ -1563,6 +1573,9 @@
"less": {
"optional": true
},
+ "lightningcss": {
+ "optional": true
+ },
"sass": {
"optional": true
},
@@ -1610,156 +1623,156 @@
}
},
"@esbuild/android-arm": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz",
- "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.16.tgz",
+ "integrity": "sha512-gCHjjQmA8L0soklKbLKA6pgsLk1byULuHe94lkZDzcO3/Ta+bbeewJioEn1Fr7kgy9NWNFy/C+MrBwC6I/WCug==",
"dev": true,
"optional": true
},
"@esbuild/android-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz",
- "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.16.tgz",
+ "integrity": "sha512-wsCqSPqLz+6Ov+OM4EthU43DyYVVyfn15S4j1bJzylDpc1r1jZFFfJQNfDuT8SlgwuqpmpJXK4uPlHGw6ve7eA==",
"dev": true,
"optional": true
},
"@esbuild/android-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz",
- "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.16.tgz",
+ "integrity": "sha512-ldsTXolyA3eTQ1//4DS+E15xl0H/3DTRJaRL0/0PgkqDsI0fV/FlOtD+h0u/AUJr+eOTlZv4aC9gvfppo3C4sw==",
"dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz",
- "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.16.tgz",
+ "integrity": "sha512-aBxruWCII+OtluORR/KvisEw0ALuw/qDQWvkoosA+c/ngC/Kwk0lLaZ+B++LLS481/VdydB2u6tYpWxUfnLAIw==",
"dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz",
- "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.16.tgz",
+ "integrity": "sha512-6w4Dbue280+rp3LnkgmriS1icOUZDyPuZo/9VsuMUTns7SYEiOaJ7Ca1cbhu9KVObAWfmdjUl4gwy9TIgiO5eA==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz",
- "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.16.tgz",
+ "integrity": "sha512-x35fCebhe9s979DGKbVAwXUOcTmCIE32AIqB9CB1GralMIvxdnMLAw5CnID17ipEw9/3MvDsusj/cspYt2ZLNQ==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz",
- "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.16.tgz",
+ "integrity": "sha512-YM98f+PeNXF3GbxIJlUsj+McUWG1irguBHkszCIwfr3BXtXZsXo0vqybjUDFfu9a8Wr7uUD/YSmHib+EeGAFlg==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz",
- "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.16.tgz",
+ "integrity": "sha512-b5ABb+5Ha2C9JkeZXV+b+OruR1tJ33ePmv9ZwMeETSEKlmu/WJ45XTTG+l6a2KDsQtJJ66qo/hbSGBtk0XVLHw==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz",
- "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.16.tgz",
+ "integrity": "sha512-XIqhNUxJiuy+zsR77+H5Z2f7s4YRlriSJKtvx99nJuG5ATuJPjmZ9n0ANgnGlPCpXGSReFpgcJ7O3SMtzIFeiQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz",
- "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.16.tgz",
+ "integrity": "sha512-no+pfEpwnRvIyH+txbBAWtjxPU9grslmTBfsmDndj7bnBmr55rOo/PfQmRfz7Qg9isswt1FP5hBbWb23fRWnow==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz",
- "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.16.tgz",
+ "integrity": "sha512-Zbnczs9ZXjmo0oZSS0zbNlJbcwKXa/fcNhYQjahDs4Xg18UumpXG/lwM2lcSvHS3mTrRyCYZvJbmzYc4laRI1g==",
"dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz",
- "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.16.tgz",
+ "integrity": "sha512-YMF7hih1HVR/hQVa/ot4UVffc5ZlrzEb3k2ip0nZr1w6fnYypll9td2qcoMLvd3o8j3y6EbJM3MyIcXIVzXvQQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz",
- "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.16.tgz",
+ "integrity": "sha512-Wkz++LZ29lDwUyTSEnzDaaP5OveOgTU69q9IyIw9WqLRxM4BjTBjz9un4G6TOvehWpf/J3gYVFN96TjGHrbcNQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz",
- "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.16.tgz",
+ "integrity": "sha512-LFMKZ30tk78/mUv1ygvIP+568bwf4oN6reG/uczXnz6SvFn4e2QUFpUpZY9iSJT6Qpgstrhef/nMykIXZtZWGQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz",
- "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.16.tgz",
+ "integrity": "sha512-3ZC0BgyYHYKfZo3AV2/66TD/I9tlSBaW7eWTEIkrQQKfJIifKMMttXl9FrAg+UT0SGYsCRLI35Gwdmm96vlOjg==",
"dev": true,
"optional": true
},
"@esbuild/linux-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz",
- "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.16.tgz",
+ "integrity": "sha512-xu86B3647DihHJHv/wx3NCz2Dg1gjQ8bbf9cVYZzWKY+gsvxYmn/lnVlqDRazObc3UMwoHpUhNYaZset4X8IPA==",
"dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz",
- "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.16.tgz",
+ "integrity": "sha512-uVAgpimx9Ffw3xowtg/7qQPwHFx94yCje+DoBx+LNm2ePDpQXHrzE+Sb0Si2VBObYz+LcRps15cq+95YM7gkUw==",
"dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz",
- "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.16.tgz",
+ "integrity": "sha512-6OjCQM9wf7z8/MBi6BOWaTL2AS/SZudsZtBziXMtNI8r/U41AxS9x7jn0ATOwVy08OotwkPqGRMkpPR2wcTJXA==",
"dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz",
- "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.16.tgz",
+ "integrity": "sha512-ZoNkruFYJp9d1LbUYCh8awgQDvB9uOMZqlQ+gGEZR7v6C+N6u7vPr86c+Chih8niBR81Q/bHOSKGBK3brJyvkQ==",
"dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz",
- "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.16.tgz",
+ "integrity": "sha512-+j4anzQ9hrs+iqO+/wa8UE6TVkKua1pXUb0XWFOx0FiAj6R9INJ+WE//1/Xo6FG1vB5EpH3ko+XcgwiDXTxcdw==",
"dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz",
- "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.16.tgz",
+ "integrity": "sha512-5PFPmq3sSKTp9cT9dzvI67WNfRZGvEVctcZa1KGjDDu4n3H8k59Inbk0du1fz0KrAbKKNpJbdFXQMDUz7BG4rQ==",
"dev": true,
"optional": true
},
"@esbuild/win32-x64": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz",
- "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.16.tgz",
+ "integrity": "sha512-sCIVrrtcWN5Ua7jYXNG1xD199IalrbfV2+0k/2Zf2OyV2FtnQnMgdzgpRAbi4AWlKJj1jkX+M+fEGPQj6BQB4w==",
"dev": true,
"optional": true
},
@@ -1842,33 +1855,33 @@
}
},
"@sveltejs/vite-plugin-svelte": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.1.tgz",
- "integrity": "sha512-bNNKvoRY89ptY7udeBSCmTdCVwkjmMcZ0j/z9J5MuedT8jPjq0zrknAo/jF1sToAza4NVaAgR9AkZoD9oJJmnA==",
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-2.4.3.tgz",
+ "integrity": "sha512-NY2h+B54KHZO3kDURTdARqthn6D4YSIebtfW75NvZ/fwyk4G+AJw3V/i0OBjyN4406Ht9yZcnNWMuRUFnDNNiA==",
"dev": true,
"requires": {
- "@sveltejs/vite-plugin-svelte-inspector": "^1.0.2",
+ "@sveltejs/vite-plugin-svelte-inspector": "^1.0.3",
"debug": "^4.3.4",
"deepmerge": "^4.3.1",
"kleur": "^4.1.5",
- "magic-string": "^0.30.0",
- "svelte-hmr": "^0.15.1",
+ "magic-string": "^0.30.1",
+ "svelte-hmr": "^0.15.2",
"vitefu": "^0.2.4"
}
},
"@sveltejs/vite-plugin-svelte-inspector": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.2.tgz",
- "integrity": "sha512-Cy1dUMcYCnDVV/hPLXa43YZJ2jGKVW5rA0xuNL9dlmYhT0yoS1g7+FOFSRlgk0BXKk/Oc7grs+8BVA5Iz2fr8A==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-1.0.3.tgz",
+ "integrity": "sha512-Khdl5jmmPN6SUsVuqSXatKpQTMIifoQPDanaxC84m9JxIibWvSABJyHpyys0Z+1yYrxY5TTEQm+6elh0XCMaOA==",
"dev": true,
"requires": {
"debug": "^4.3.4"
}
},
"@tsconfig/svelte": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-4.0.1.tgz",
- "integrity": "sha512-B+XlGpmuAQzJqDoBATNCvEPqQg0HkO7S8pM14QDI5NsmtymzRexQ1N+nX2H6RTtFbuFgaZD4I8AAi8voGg0GLg==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.0.tgz",
+ "integrity": "sha512-iu5BqFjU0+OcLTNQp7fHe6Bf6zdNeJ9IZjLZMqWLuGzVFm/xx+lm//Tf6koPyRmxo55/Snm6RRQ990n89cRKFw==",
"dev": true
},
"@types/estree": {
@@ -1900,9 +1913,9 @@
}
},
"aria-query": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.2.1.tgz",
- "integrity": "sha512-7uFg4b+lETFgdaJyETnILsXgnnzVnkHcgRbwbPwevm5x/LmUlt3MjczMRe1zg824iBgXZNRPTBftNYyRSKLp2g==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"requires": {
"dequal": "^2.0.3"
@@ -1961,9 +1974,9 @@
"dev": true
},
"chart.js": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.0.tgz",
- "integrity": "sha512-ynG0E79xGfMaV2xAHdbhwiPLczxnNNnasrmPEXriXsPJGjmhOBYzFVEsB65w2qMDz+CaBJJuJD0inE/ab/h36g==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.3.1.tgz",
+ "integrity": "sha512-QHuISG3hTJ0ftq0I0f5jqH9mNVO9bqG8P+zvMOVslgKajQVvFEX7QAhYNJ+QEmw+uYTwo8XpTimaB82oeTWjxw==",
"requires": {
"@kurkle/color": "^0.3.0"
}
@@ -1997,6 +2010,11 @@
"periscopic": "^3.1.0"
}
},
+ "comlink": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/comlink/-/comlink-4.4.1.tgz",
+ "integrity": "sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q=="
+ },
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2047,33 +2065,33 @@
"dev": true
},
"esbuild": {
- "version": "0.17.19",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz",
- "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==",
+ "version": "0.18.16",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.16.tgz",
+ "integrity": "sha512-1xLsOXrDqwdHxyXb/x/SOyg59jpf/SH7YMvU5RNSU7z3TInaASNJWNFJ6iRvLvLETZMasF3d1DdZLg7sgRimRQ==",
"dev": true,
"requires": {
- "@esbuild/android-arm": "0.17.19",
- "@esbuild/android-arm64": "0.17.19",
- "@esbuild/android-x64": "0.17.19",
- "@esbuild/darwin-arm64": "0.17.19",
- "@esbuild/darwin-x64": "0.17.19",
- "@esbuild/freebsd-arm64": "0.17.19",
- "@esbuild/freebsd-x64": "0.17.19",
- "@esbuild/linux-arm": "0.17.19",
- "@esbuild/linux-arm64": "0.17.19",
- "@esbuild/linux-ia32": "0.17.19",
- "@esbuild/linux-loong64": "0.17.19",
- "@esbuild/linux-mips64el": "0.17.19",
- "@esbuild/linux-ppc64": "0.17.19",
- "@esbuild/linux-riscv64": "0.17.19",
- "@esbuild/linux-s390x": "0.17.19",
- "@esbuild/linux-x64": "0.17.19",
- "@esbuild/netbsd-x64": "0.17.19",
- "@esbuild/openbsd-x64": "0.17.19",
- "@esbuild/sunos-x64": "0.17.19",
- "@esbuild/win32-arm64": "0.17.19",
- "@esbuild/win32-ia32": "0.17.19",
- "@esbuild/win32-x64": "0.17.19"
+ "@esbuild/android-arm": "0.18.16",
+ "@esbuild/android-arm64": "0.18.16",
+ "@esbuild/android-x64": "0.18.16",
+ "@esbuild/darwin-arm64": "0.18.16",
+ "@esbuild/darwin-x64": "0.18.16",
+ "@esbuild/freebsd-arm64": "0.18.16",
+ "@esbuild/freebsd-x64": "0.18.16",
+ "@esbuild/linux-arm": "0.18.16",
+ "@esbuild/linux-arm64": "0.18.16",
+ "@esbuild/linux-ia32": "0.18.16",
+ "@esbuild/linux-loong64": "0.18.16",
+ "@esbuild/linux-mips64el": "0.18.16",
+ "@esbuild/linux-ppc64": "0.18.16",
+ "@esbuild/linux-riscv64": "0.18.16",
+ "@esbuild/linux-s390x": "0.18.16",
+ "@esbuild/linux-x64": "0.18.16",
+ "@esbuild/netbsd-x64": "0.18.16",
+ "@esbuild/openbsd-x64": "0.18.16",
+ "@esbuild/sunos-x64": "0.18.16",
+ "@esbuild/win32-arm64": "0.18.16",
+ "@esbuild/win32-ia32": "0.18.16",
+ "@esbuild/win32-x64": "0.18.16"
}
},
"estree-walker": {
@@ -2236,12 +2254,12 @@
"dev": true
},
"magic-string": {
- "version": "0.30.0",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
- "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==",
+ "version": "0.30.1",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
+ "integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==",
"dev": true,
"requires": {
- "@jridgewell/sourcemap-codec": "^1.4.13"
+ "@jridgewell/sourcemap-codec": "^1.4.15"
}
},
"mdn-data": {
@@ -2368,9 +2386,9 @@
"dev": true
},
"postcss": {
- "version": "8.4.24",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
- "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
+ "version": "8.4.27",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
+ "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"dev": true,
"requires": {
"nanoid": "^3.3.6",
@@ -2415,9 +2433,9 @@
}
},
"rollup": {
- "version": "3.25.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz",
- "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==",
+ "version": "3.26.3",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.3.tgz",
+ "integrity": "sha512-7Tin0C8l86TkpcMtXvQu6saWH93nhG3dGQ1/+l5V2TDMceTxO7kDiK6GzbfLWNNxqJXm591PcEZUozZm51ogwQ==",
"dev": true,
"requires": {
"fsevents": "~2.3.2"
@@ -2481,16 +2499,16 @@
}
},
"svelte": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.0.0.tgz",
- "integrity": "sha512-+yCYu3AEUu9n91dnQNGIbnVp8EmNQtuF/YImW4+FTXRHard7NMo+yTsWzggPAbj3fUEJ1FBJLkql/jkp6YB5pg==",
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.1.1.tgz",
+ "integrity": "sha512-Enick5fPFISLoVy0MFK45cG+YlQt6upw8skEK9zzTpJnH1DqEv8xOZwizCGSo3Q6HZ7KrZTM0J18poF7aQg5zw==",
"dev": true,
"requires": {
"@ampproject/remapping": "^2.2.1",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@jridgewell/trace-mapping": "^0.3.18",
- "acorn": "^8.8.2",
- "aria-query": "^5.2.1",
+ "acorn": "^8.9.0",
+ "aria-query": "^5.3.0",
"axobject-query": "^3.2.1",
"code-red": "^1.0.3",
"css-tree": "^2.3.1",
@@ -2502,9 +2520,9 @@
}
},
"svelte-check": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.4.3.tgz",
- "integrity": "sha512-O07soQFY3X0VDt+bcGc6D5naz0cLtjwnmNP9JsEBPVyMemFEqUhL2OdLqvkl5H/u8Jwm50EiAU4BPRn5iin/kg==",
+ "version": "3.4.6",
+ "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.4.6.tgz",
+ "integrity": "sha512-OBlY8866Zh1zHQTkBMPS6psPi7o2umTUyj6JWm4SacnIHXpWFm658pG32m3dKvKFL49V4ntAkfFHKo4ztH07og==",
"dev": true,
"requires": {
"@jridgewell/trace-mapping": "^0.3.17",
@@ -2513,7 +2531,7 @@
"import-fresh": "^3.2.1",
"picocolors": "^1.0.0",
"sade": "^1.7.4",
- "svelte-preprocess": "^5.0.3",
+ "svelte-preprocess": "^5.0.4",
"typescript": "^5.0.3"
}
},
@@ -2558,27 +2576,27 @@
}
},
"tslib": {
- "version": "2.5.3",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz",
- "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==",
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
+ "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==",
"dev": true
},
"typescript": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
- "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
+ "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==",
"dev": true
},
"vite": {
- "version": "4.3.9",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
- "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
+ "version": "4.4.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.7.tgz",
+ "integrity": "sha512-6pYf9QJ1mHylfVh39HpuSfMPojPSKVxZvnclX1K1FyZ1PXDOcLBibdq5t1qxJSnL63ca8Wf4zts6mD8u8oc9Fw==",
"dev": true,
"requires": {
- "esbuild": "^0.17.5",
+ "esbuild": "^0.18.10",
"fsevents": "~2.3.2",
- "postcss": "^8.4.23",
- "rollup": "^3.21.0"
+ "postcss": "^8.4.26",
+ "rollup": "^3.25.2"
}
},
"vitefu": {
diff --git a/development/plot-benchmarks/package.json b/development/plot-benchmarks/package.json
index 28ee731..d65f5a2 100644
--- a/development/plot-benchmarks/package.json
+++ b/development/plot-benchmarks/package.json
@@ -10,15 +10,16 @@
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
- "@sveltejs/vite-plugin-svelte": "^2.4.1",
- "@tsconfig/svelte": "^4.0.1",
- "svelte": "^4.0.0",
- "svelte-check": "^3.4.3",
- "tslib": "^2.5.0",
- "typescript": "^5.0.0",
- "vite": "^4.3.9"
+ "@sveltejs/vite-plugin-svelte": "^2.4.3",
+ "@tsconfig/svelte": "^5.0.0",
+ "svelte": "^4.1.1",
+ "svelte-check": "^3.4.6",
+ "tslib": "^2.6.1",
+ "typescript": "^5.1.6",
+ "vite": "^4.4.7"
},
"dependencies": {
- "chart.js": "^4.3.0"
+ "chart.js": "^4.3.1",
+ "comlink": "4.4.1"
}
}
\ No newline at end of file
diff --git a/development/plot-benchmarks/src/lib/App.svelte b/development/plot-benchmarks/src/lib/App.svelte
index ffa3e57..f1ace88 100644
--- a/development/plot-benchmarks/src/lib/App.svelte
+++ b/development/plot-benchmarks/src/lib/App.svelte
@@ -3,9 +3,17 @@
import { writable } from "svelte/store";
import type { FileMetadata } from "../types/files.js";
import Session from "./Session.svelte";
+ import { wrap } from "comlink";
+ import { StatService } from "../workers/service.js";
// Stores
let entries: Writable<FileMetadata[]> = writable([]);
+ const url = new URL("../workers/worker.ts", import.meta.url);
+ const service = wrap<StatService>(
+ new Worker(url, {
+ type: "module",
+ })
+ );
function onFilesChanged(event) {
const detail: FileMetadata[] = event.detail;
@@ -22,5 +30,5 @@
</details>
<div class="container">
- <Session fileEntries={$entries} on:entries={onFilesChanged} />
+ <Session fileEntries={$entries} {service} on:entries={onFilesChanged} />
</div>
diff --git a/development/plot-benchmarks/src/lib/Chart.svelte b/development/plot-benchmarks/src/lib/Chart.svelte
index 7a063a8..9a224e2 100644
--- a/development/plot-benchmarks/src/lib/Chart.svelte
+++ b/development/plot-benchmarks/src/lib/Chart.svelte
@@ -10,6 +10,7 @@
export let data: Data;
export let chartType: ChartType = "line";
+ export let isExperimental: boolean = false;
$: {
if ($chart) {
@@ -27,7 +28,9 @@
onMount(() => {
const onUpdate = (chart: Chart) => {
$chart = chart;
- $items = chart.options.plugins.legend.labels.generateLabels(chart);
+ // Bad typings.
+ const legend = chart.options.plugins.legend as any;
+ $items = legend.labels.generateLabels(chart);
};
const plugins = {
legend: {
@@ -65,7 +68,14 @@
⎘
</button>
</div>
- <canvas id="chart" class="chart" bind:this={element} />
+ <canvas class="chart" bind:this={element} />
+ {#if isExperimental}
+ <footer class="slim">
+ <section class="experimental">
+ <kbd>Experimental</kbd>
+ </section>
+ </footer>
+ {/if}
</article>
{#if $items}
@@ -89,4 +99,17 @@
border: none;
padding: 5px;
}
+
+ .slim {
+ margin-bottom: 0px;
+ padding: 0;
+ }
+
+ .experimental {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: center;
+ margin-bottom: 0px;
+ }
</style>
diff --git a/development/plot-benchmarks/src/lib/Dataset.svelte b/development/plot-benchmarks/src/lib/Dataset.svelte
index a19eff0..a435bae 100644
--- a/development/plot-benchmarks/src/lib/Dataset.svelte
+++ b/development/plot-benchmarks/src/lib/Dataset.svelte
@@ -1,14 +1,27 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
+ import {
+ type DatasetSelection,
+ type DatasetSelectionEvent,
+ type MetricSelection,
+ type MetricSelectionEvent,
+ type StatEvent,
+ type StatInfo,
+ type StatType,
+ } from "../types/events.js";
import { Session, type IndexedWrapper } from "../wrappers/session.js";
- import type { SelectionEvent, Selection } from "../types/events.js";
export let name: string;
export let datasetGroup: IndexedWrapper[];
+ export let suppressedMetrics: Set<string>;
+ // Dispatchers
+ let datasetDispatcher = createEventDispatcher<DatasetSelectionEvent>();
+ let metricsDispatcher = createEventDispatcher<MetricSelectionEvent>();
+ let statDispatcher = createEventDispatcher<StatEvent>();
// State
- let dispatcher = createEventDispatcher<SelectionEvent>();
let selected: boolean = true;
+ let compute: boolean = false;
let sources: Set<string>;
let sampledMetrics: Set<string>;
let metrics: Set<string>;
@@ -18,16 +31,42 @@
event.stopPropagation();
const target = event.target as HTMLInputElement;
selected = target.checked;
- const selection: Selection = {
+ const selection: DatasetSelection = {
name: name,
enabled: selected,
};
- dispatcher("selections", [selection]);
+ datasetDispatcher("datasetSelections", [selection]);
+ };
+
+ let stat = function (type: StatType) {
+ return function (event: Event) {
+ event.stopPropagation();
+ const target = event.target as HTMLInputElement;
+ compute = target.checked;
+ const stat: StatInfo = {
+ name: name,
+ type: type,
+ enabled: compute,
+ };
+ statDispatcher("info", [stat]);
+ };
+ };
+
+ let metricSelection = function (metric: string) {
+ return function (event: Event) {
+ event.stopPropagation();
+ const target = event.target as HTMLInputElement;
+ const checked = target.checked;
+ const selection: MetricSelection = {
+ name: metric,
+ enabled: checked,
+ };
+ metricsDispatcher("metricSelections", [selection]);
+ };
};
$: {
sources = Session.sources(datasetGroup);
-
let labels = datasetGroup
.map((indexed) => indexed.value.metricLabels())
.flat();
@@ -45,16 +84,32 @@
<hgroup>
<div class="section">
<span class="item">{name}</span>
- <fieldset class="item">
- <label for="switch">
- <input
- type="checkbox"
- role="switch"
- checked={selected}
- on:change={selection}
- />
- </label>
- </fieldset>
+ <div class="item actions">
+ <fieldset>
+ <label for="switch">
+ Show
+ <input
+ type="checkbox"
+ role="switch"
+ checked={selected}
+ on:change={selection}
+ />
+ </label>
+ </fieldset>
+ {#if sources.size > 1}
+ <fieldset>
+ <label for="switch">
+ P
+ <input
+ type="checkbox"
+ role="switch"
+ checked={compute}
+ on:change={stat("p")}
+ />
+ </label>
+ </fieldset>
+ {/if}
+ </div>
</div>
<div class="details">
<div class="sources">
@@ -64,15 +119,37 @@
</div>
{#if metrics.size > 0}
<div class="metrics">
- {#each metrics as metric}
- <div>📏 <small>{metric}</small></div>
+ {#each metrics as metric (metric)}
+ <fieldset class="metric">
+ <label for={metric}>
+ <input
+ type="checkbox"
+ name={metric}
+ id={metric}
+ checked={!suppressedMetrics.has(metric)}
+ on:change={metricSelection(metric)}
+ />
+ 📏 {metric}
+ </label>
+ </fieldset>
{/each}
</div>
{/if}
{#if sampledMetrics.size > 0}
<div class="sampled">
- {#each sampledMetrics as metric}
- <div>📏 <small>{metric}</small></div>
+ {#each sampledMetrics as metric (metric)}
+ <fieldset class="metric">
+ <label for={metric}>
+ <input
+ type="checkbox"
+ name={metric}
+ id={metric}
+ checked={!suppressedMetrics.has(metric)}
+ on:change={metricSelection(metric)}
+ />
+ 📏 {metric}
+ </label>
+ </fieldset>
{/each}
</div>
{/if}
@@ -103,4 +180,18 @@
.section .item {
margin: 0px 10px;
}
+ .actions {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-end;
+ }
+ .actions fieldset {
+ margin-left: 5px;
+ }
+ .metric {
+ margin-bottom: 0;
+ }
+ .metric label {
+ font-size: 0.875em;
+ }
</style>
diff --git a/development/plot-benchmarks/src/lib/Group.svelte b/development/plot-benchmarks/src/lib/Group.svelte
index e538e68..c5f4da6 100644
--- a/development/plot-benchmarks/src/lib/Group.svelte
+++ b/development/plot-benchmarks/src/lib/Group.svelte
@@ -1,18 +1,36 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
- import type { Selection, SelectionEvent } from "../types/events.js";
+ import type {
+ DatasetSelection,
+ DatasetSelectionEvent,
+ MetricSelection,
+ MetricSelectionEvent,
+ StatEvent,
+ StatInfo,
+ } from "../types/events.js";
import { Session, type IndexedWrapper } from "../wrappers/session.js";
import Dataset from "./Dataset.svelte";
export let className: string;
export let datasetGroup: IndexedWrapper[];
+ export let suppressedMetrics: Set<string>;
- let dispatcher = createEventDispatcher<SelectionEvent>();
+ let datasetDispatcher = createEventDispatcher<DatasetSelectionEvent>();
+ let metricsDispatcher = createEventDispatcher<MetricSelectionEvent>();
+ let statDispatcher = createEventDispatcher<StatEvent>();
let datasetNames: Set<string>;
- let selection = function (event: CustomEvent<Selection[]>) {
- // Forward events.
- dispatcher("selections", event.detail);
+ // Forward events.
+ let datasetSelection = function (event: CustomEvent<DatasetSelection[]>) {
+ datasetDispatcher("datasetSelections", event.detail);
+ };
+
+ let stat = function (event: CustomEvent<StatInfo[]>) {
+ statDispatcher("info", event.detail);
+ };
+
+ let metricSelection = function (event: CustomEvent<MetricSelection[]>) {
+ metricsDispatcher("metricSelections", event.detail);
};
$: {
@@ -24,7 +42,14 @@
<summary>{className}</summary>
<div class="details">
{#each datasetNames as name (name)}
- <Dataset {datasetGroup} {name} on:selections={selection} />
+ <Dataset
+ {datasetGroup}
+ {suppressedMetrics}
+ {name}
+ on:datasetSelections={datasetSelection}
+ on:metricSelections={metricSelection}
+ on:info={stat}
+ />
{/each}
</div>
</details>
diff --git a/development/plot-benchmarks/src/lib/Session.svelte b/development/plot-benchmarks/src/lib/Session.svelte
index b751f67..e70f88c 100644
--- a/development/plot-benchmarks/src/lib/Session.svelte
+++ b/development/plot-benchmarks/src/lib/Session.svelte
@@ -1,19 +1,32 @@
<script lang="ts">
import { createEventDispatcher } from "svelte";
- import { writable, type Writable } from "svelte/store";
+ import {
+ writable,
+ type Readable,
+ type Writable,
+ derived,
+ } from "svelte/store";
import { readBenchmarks } from "../files.js";
import { ChartDataTransforms } from "../transforms/data-transforms.js";
import { Transforms } from "../transforms/metric-transforms.js";
import { STANDARD_MAPPER } from "../transforms/standard-mappers.js";
import type { Data, Series } from "../types/chart.js";
import type { Metrics } from "../types/data.js";
- import type { FileMetadataEvent, Selection } from "../types/events.js";
+ import type {
+ FileMetadataEvent,
+ DatasetSelection,
+ StatInfo,
+ MetricSelection,
+ } from "../types/events.js";
import type { FileMetadata } from "../types/files.js";
import { Session, type IndexedWrapper } from "../wrappers/session.js";
import Chart from "./Chart.svelte";
import Group from "./Group.svelte";
+ import type { StatService } from "../workers/service.js";
+ import type { Remote } from "comlink";
export let fileEntries: FileMetadata[];
+ export let service: Remote<StatService>;
// State
let eventDispatcher = createEventDispatcher<FileMetadataEvent>();
@@ -23,14 +36,25 @@
let chartData: Data;
let classGroups: Record<string, IndexedWrapper[]>;
let size: number;
+ let activeSeries: Promise<Series[]>;
// Stores
let activeDragDrop: Writable<boolean> = writable(false);
let suppressed: Writable<Set<string>> = writable(new Set());
+ let suppressedMetrics: Writable<Set<string>> = writable(new Set());
+ let activeStats: Writable<StatInfo[]> = writable([]);
+ let active: Readable<Set<string>> = derived(activeStats, ($activeStats) => {
+ const datasets = [];
+ for (let i = 0; i < $activeStats.length; i += 1) {
+ const activeStat = $activeStats[i];
+ datasets.push(activeStat.name);
+ }
+ return new Set(datasets);
+ });
// Events
- let handler = function (event: CustomEvent<Selection[]>) {
- const selections: Selection[] = event.detail;
+ let datasetHandler = function (event: CustomEvent<DatasetSelection[]>) {
+ const selections: DatasetSelection[] = event.detail;
for (let i = 0; i < selections.length; i += 1) {
const selection = selections[i];
if (!selection.enabled) {
@@ -42,9 +66,41 @@
$suppressed = $suppressed;
};
+ let metricsHandler = function (event: CustomEvent<MetricSelection[]>) {
+ const selections: MetricSelection[] = event.detail;
+ for (let i = 0; i < selections.length; i += 1) {
+ const selection = selections[i];
+ if (!selection.enabled) {
+ $suppressedMetrics.add(selection.name);
+ } else {
+ $suppressedMetrics.delete(selection.name);
+ }
+ }
+ $suppressedMetrics = $suppressedMetrics;
+ };
+
+ let statHandler = function (event: CustomEvent<StatInfo[]>) {
+ const statistics = event.detail;
+ for (let i = 0; i < statistics.length; i += 1) {
+ const statInfo = statistics[i];
+ if (!statInfo.enabled) {
+ const index = $activeStats.findIndex(
+ (entry) => entry.name == statInfo.name && entry.type == statInfo.type
+ );
+ if (index >= 0) {
+ $activeStats.splice(index, 1);
+ }
+ } else {
+ $activeStats.push(statInfo);
+ }
+ $activeStats = $activeStats;
+ }
+ };
+
$: {
session = new Session(fileEntries);
- metrics = Transforms.buildMetrics(session, $suppressed);
+ metrics = Transforms.buildMetrics(session, $suppressed, $suppressedMetrics);
+ activeSeries = service.pSeries(metrics, $active);
series = ChartDataTransforms.mapToSeries(metrics, STANDARD_MAPPER);
chartData = ChartDataTransforms.mapToDataset(series);
classGroups = session.classGroups;
@@ -115,13 +171,31 @@
>
<h5>Benchmarks</h5>
{#each Object.entries(classGroups) as [className, wrappers]}
- <Group {className} datasetGroup={wrappers} on:selections={handler} />
+ <Group
+ {className}
+ datasetGroup={wrappers}
+ suppressedMetrics={$suppressedMetrics}
+ on:datasetSelections={datasetHandler}
+ on:metricSelections={metricsHandler}
+ on:info={statHandler}
+ />
{/each}
</article>
{#if series.length > 0}
<Chart data={chartData} />
{/if}
+
+ {#await activeSeries}
+ <article aria-busy="true" />
+ {:then chartData}
+ {#if chartData.length > 0}
+ <Chart
+ data={ChartDataTransforms.mapToDataset(chartData)}
+ isExperimental={true}
+ />
+ {/if}
+ {/await}
{/if}
<style>
diff --git a/development/plot-benchmarks/src/transforms/metric-transforms.ts b/development/plot-benchmarks/src/transforms/metric-transforms.ts
index e35da44..370b6a6 100644
--- a/development/plot-benchmarks/src/transforms/metric-transforms.ts
+++ b/development/plot-benchmarks/src/transforms/metric-transforms.ts
@@ -9,7 +9,7 @@
// static helpers.
}
- static buildMetrics(session: Session, suppressed: Set<string>): Metrics<number> {
+ static buildMetrics(session: Session, suppressed: Set<string>, suppressedMetrics: Set<string>): Metrics<number> {
const classGroups = Object.entries(session.classGroups);
const standard: Metric<number>[] = [];
const sampled: Metric<number[]>[] = [];
@@ -19,7 +19,6 @@
const wrapper = wrappers[j];
const datasetName = wrappers[j].value.datasetName();
if (suppressed.has(datasetName)) {
- console.log(`Skipping suppressed dataset name ${datasetName}`, session);
continue;
}
const source = wrapper.source;
@@ -28,6 +27,9 @@
let labels = wrapper.value.metricLabels();
for (let k = 0; k < labels.length; k += 1) {
const label = labels[k];
+ if (suppressedMetrics.has(label)) {
+ continue;
+ }
const metric = wrapper.value.metric(label);
const charData: ChartData<number> = {
values: metric.runs
@@ -45,6 +47,9 @@
labels = wrapper.value.sampledLabels();
for (let k = 0; k < labels.length; k += 1) {
const label = labels[k];
+ if (suppressedMetrics.has(label)) {
+ continue;
+ }
const metric = wrapper.value.sampled(label);
const charData: ChartData<number[]> = {
values: metric.runs
diff --git a/development/plot-benchmarks/src/transforms/standard-mappers.ts b/development/plot-benchmarks/src/transforms/standard-mappers.ts
index 8b928cd..6b3646a 100644
--- a/development/plot-benchmarks/src/transforms/standard-mappers.ts
+++ b/development/plot-benchmarks/src/transforms/standard-mappers.ts
@@ -10,7 +10,7 @@
for (let i = 0; i < entries.length; i += 1) {
const [source, chartData] = entries[i];
const label = labelFor(metric, source);
- const points = histogramPoints(chartData.values);
+ const [points, _, __] = histogramPoints(chartData.values);
series.push({
label: label,
type: "line",
@@ -43,20 +43,51 @@
return series;
}
-function histogramPoints(runs: number[][], buckets: number = 10): Point[] {
+export function histogramPoints(
+ runs: number[][],
+ buckets: number = 10,
+ target: number | null = null
+): [Point[], Point[] | null, number | null] {
const flattened = runs.flat();
// Default comparator coerces types to string !
flattened.sort((a, b) => a - b); // in-place
const min = flattened[0];
const max = flattened[flattened.length - 1];
+ let targetPoints: Point[] | null = null;
+ let pN: number = 0;
+ let maxFreq: number = 0;
const histogram = new Array(buckets).fill(0);
const slots = buckets - 1; // The actual number of slots in the histogram
for (let i = 0; i < flattened.length; i += 1) {
- let n = normalize(flattened[i], min, max);
- let index = Math.ceil(n * slots);
+ const value = flattened[i];
+ if (value >= target) {
+ pN += 1;
+ }
+ const n = normalize(value, min, max);
+ const index = Math.ceil(n * slots);
histogram[index] = histogram[index] + 1;
+ if (maxFreq < histogram[index]) {
+ maxFreq = histogram[index];
+ }
}
- return singlePoints(histogram);
+ if (target) {
+ const n = normalize(target, min, max);
+ const index = Math.ceil(n * slots);
+ targetPoints = selectPoints(buckets, index, maxFreq);
+ }
+ return [singlePoints(histogram), targetPoints, (pN / flattened.length)];
+}
+
+function selectPoints(buckets: number, index: number, target: number) {
+ const points: Point[] = [];
+ for (let i = 0; i < buckets; i += 1) {
+ const y = i == index ? target : 0;
+ points.push({
+ x: i + 1, // 1 based index
+ y: y
+ });
+ }
+ return points;
}
function singlePoints(runs: number[]): Point[] {
@@ -71,6 +102,15 @@
}
function normalize(n: number, min: number, max: number): number {
+ if (n < min || n > max) {
+ console.warn(`Warning n(${n}) is not in the range of (${min}, ${max})`);
+ if (n < min) {
+ n = min;
+ }
+ if (n > max) {
+ n = max;
+ }
+ }
return (n - min) / (max - min + 1e-5);
}
@@ -78,7 +118,11 @@
* Generates a series label.
*/
function labelFor<T>(metric: Metric<T>, source: string): string {
- return `${source}[${metric.class} ${metric.benchmark} ${metric.label}]`;
+ return `${source} {${metric.class}${metric.benchmark}} - ${metric.label}`;
+}
+
+export function datasetName(metric: Metric<any>): string {
+ return `${metric.class}_${metric.benchmark}`;
}
/**
diff --git a/development/plot-benchmarks/src/types/events.ts b/development/plot-benchmarks/src/types/events.ts
index 4dbe7d3b..72890d4 100644
--- a/development/plot-benchmarks/src/types/events.ts
+++ b/development/plot-benchmarks/src/types/events.ts
@@ -1,13 +1,33 @@
import type { FileMetadata } from "./files.js";
export interface FileMetadataEvent {
- entries: Array<FileMetadata>;
+ entries: FileMetadata[];
}
-export interface Selection {
+export interface DatasetSelection {
name: string;
enabled: boolean;
}
-export interface SelectionEvent {
- selections: Array<Selection>;
+export interface DatasetSelectionEvent {
+ datasetSelections: DatasetSelection[];
+}
+
+export interface MetricSelectionEvent {
+ metricSelections: MetricSelection[];
+}
+
+export interface MetricSelection {
+ name: string;
+ enabled: boolean;
+}
+
+export type StatType = 'p';
+export interface StatInfo {
+ name: string;
+ type: StatType;
+ enabled: boolean;
+}
+
+export interface StatEvent {
+ info: StatInfo[];
}
diff --git a/development/plot-benchmarks/src/workers/service.ts b/development/plot-benchmarks/src/workers/service.ts
new file mode 100644
index 0000000..9ee37e0
--- /dev/null
+++ b/development/plot-benchmarks/src/workers/service.ts
@@ -0,0 +1,132 @@
+import { datasetName, histogramPoints } from "../transforms/standard-mappers.js";
+import type { Series } from "../types/chart.js";
+import type { ChartData, Metrics } from "../types/data.js";
+
+export class StatService {
+ pSeries(metrics: Metrics<number>, activeDatasets: Set<string>): Series[] {
+ if (activeDatasets.size <= 0) {
+ return [];
+ }
+
+ const series: Series[] = [];
+ const sampled = metrics.sampled;
+ if (sampled) {
+ for (let i = 0; i < sampled.length; i += 1) {
+ const metric = sampled[i];
+ const name = datasetName(metric);
+ if (activeDatasets.has(name)) {
+ const data: Record<string, ChartData<number[]>> = metric.data;
+ const entries = Object.entries(data);
+ const comparables: ChartData<number[]>[] = entries.map(entry => entry[1]);
+ if (comparables.length > 1) {
+ const reference = comparables[0];
+ for (let j = 1; j < comparables.length; j += 1) {
+ const target = comparables[j];
+ const [delta, distribution] = this.buildDistribution(reference, target);
+ const [points, pPlots, p] = histogramPoints([distribution], 20, delta);
+ series.push({
+ label: `${name} { ${metric.label} } - Likelihood`,
+ type: "line",
+ data: points,
+ options: {
+ tension: 0.3
+ }
+ });
+ if (pPlots && pPlots.length > 0) {
+ series.push({
+ label: `${name} { ${metric.label} } - { P = ${p} }`,
+ type: "bar",
+ data: pPlots,
+ options: {
+ tension: 0.01
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+ return series;
+ }
+
+ private buildDistribution(
+ reference: ChartData<number[]>,
+ target: ChartData<number[]>,
+ N: number = 1_000
+ ): [number, number[]] {
+ // Compute delta mean
+ const referenceData = reference.values;
+ const targetData = target.values;
+ const referenceMedian = this.arrayMedian(referenceData);
+ const targetMedian = this.arrayMedian(targetData);
+ const deltaMedian = Math.abs(referenceMedian - targetMedian);
+ // Simulate
+ const rs = referenceData.length;
+ const ts = targetData.length;
+ const combined: number[][] = [...referenceData, ...targetData];
+ const medians = [];
+ for (let i = 0; i < N; i += 1) {
+ const [r, t] = this.shuffleSplit(combined, [rs, ts]);
+ const mr = this.arrayMedian(r);
+ const mt = this.arrayMedian(t);
+ medians.push(Math.abs(mr - mt));
+ }
+ return [deltaMedian, medians];
+ }
+
+ private shuffleSplit<T>(data: T[], sizes: number[]): T[][] {
+ const shuffled = this.shuffle(data);
+ const splits: T[][] = [];
+ let index = 0;
+ for (let i = 0; i < sizes.length; i += 1) {
+ const size = sizes[i];
+ let split: T[] = [];
+ for (let j = 0; j < size; j += 1) {
+ const k = index + j;
+ if (k < shuffled.length) {
+ split.push(shuffled[k]);
+ }
+ }
+ index += size;
+ splits.push(split);
+ }
+ return splits;
+ }
+
+ private arrayMedian(data: number[][]): number {
+ // We don't want to compute median of medians here.
+ // This is because while individual runs are correlated
+ // we can still look at the actual metrics in aggregate.
+ return this.median(data.flat());
+ }
+
+ private median(data: number[]): number {
+ const copy = [...data];
+ // Default comparator coerces types to string !
+ copy.sort((a, b) => a - b); // in-place
+ const length = copy.length;
+ const index = Math.trunc(length / 2);
+ return copy[index];
+ }
+
+ private shuffle<T>(data: T[], multiplier: number = 1): T[] {
+ if (data.length <= 0) {
+ return [];
+ }
+
+ let copy = [...data];
+ const count = copy.length * multiplier;
+ const slots = copy.length - 1;
+ for (let i = 0; i < count; i += 1) {
+ const sourceIndex = Math.ceil(Math.random() * slots);
+ const targetIndex = Math.ceil(Math.random() * slots);
+ let source = copy[sourceIndex];
+ let target = copy[targetIndex];
+ copy[sourceIndex] = target;
+ copy[targetIndex] = source;
+ }
+ return copy;
+ }
+
+}
diff --git a/development/plot-benchmarks/src/workers/worker.ts b/development/plot-benchmarks/src/workers/worker.ts
new file mode 100644
index 0000000..367e74c
--- /dev/null
+++ b/development/plot-benchmarks/src/workers/worker.ts
@@ -0,0 +1,10 @@
+/* Stub worker. */
+
+import { expose } from "comlink";
+import { StatService } from "./service.js";
+
+// This is always running in the context of a Web Worker.
+declare var self: Worker;
+
+const service = new StatService();
+expose(service, self);
diff --git a/development/plot-benchmarks/src/wrappers/session.ts b/development/plot-benchmarks/src/wrappers/session.ts
index 2581f92..80209dd 100644
--- a/development/plot-benchmarks/src/wrappers/session.ts
+++ b/development/plot-benchmarks/src/wrappers/session.ts
@@ -68,5 +68,4 @@
}
return sources;
}
-
}
diff --git a/development/referenceDocs/switcher.py b/development/referenceDocs/switcher.py
index 562d433..e73e4c6 100755
--- a/development/referenceDocs/switcher.py
+++ b/development/referenceDocs/switcher.py
@@ -81,14 +81,14 @@
stub = doc.replace(java_source_abs_path, kotlin_source_abs_path)
# Always add the switcher for java files, switch to the package summary if
# the page itself doesn't exist in kotlin
- slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\">/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_java_switcher2.md\" %}",doc)
+ slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\"><\/div>/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_java_switcher2.md\" %}",doc)
else:
file_path = doc[len(kotlin_ref_root)+1:]
stub = doc.replace(kotlin_source_abs_path, java_source_abs_path)
if (both):
- slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\">/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
+ slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\"><\/div>/{}/' {}".format("\\n{% setvar page_path %}_page_path_{% endsetvar %}\\n{% setvar can_switch %}1{% endsetvar %}\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
else:
- slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\">/{}/' {}".format("\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
+ slug1 = "sed -i 's/<div id=\"refdoc-switcher-placeholder\"><\/div>/{}/' {}".format("\\n{% include \"reference\/_kotlin_switcher2.md\" %}",doc)
os.system(slug1)
if both or java:
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 672052a..ad804b8 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -31,10 +31,10 @@
docs("androidx.asynclayoutinflater:asynclayoutinflater:1.1.0-alpha01")
docs("androidx.asynclayoutinflater:asynclayoutinflater-appcompat:1.1.0-alpha01")
docs("androidx.autofill:autofill:1.3.0-alpha01")
- docs("androidx.benchmark:benchmark-common:1.2.0-beta01")
- docs("androidx.benchmark:benchmark-junit4:1.2.0-beta01")
- docs("androidx.benchmark:benchmark-macro:1.2.0-beta01")
- docs("androidx.benchmark:benchmark-macro-junit4:1.2.0-beta01")
+ docs("androidx.benchmark:benchmark-common:1.2.0-beta02")
+ docs("androidx.benchmark:benchmark-junit4:1.2.0-beta02")
+ docs("androidx.benchmark:benchmark-macro:1.2.0-beta02")
+ docs("androidx.benchmark:benchmark-macro-junit4:1.2.0-beta02")
docs("androidx.biometric:biometric:1.2.0-alpha05")
docs("androidx.biometric:biometric-ktx:1.2.0-alpha05")
samples("androidx.biometric:biometric-ktx-samples:1.2.0-alpha05")
@@ -129,9 +129,9 @@
docs("androidx.core:core-testing:1.12.0-beta01")
docs("androidx.core.uwb:uwb:1.0.0-alpha06")
docs("androidx.core.uwb:uwb-rxjava3:1.0.0-alpha06")
- docs("androidx.credentials:credentials:1.2.0-beta01")
- docs("androidx.credentials:credentials-play-services-auth:1.2.0-beta01")
- samples("androidx.credentials:credentials-samples:1.2.0-beta01")
+ docs("androidx.credentials:credentials:1.2.0-beta02")
+ docs("androidx.credentials:credentials-play-services-auth:1.2.0-beta02")
+ samples("androidx.credentials:credentials-samples:1.2.0-beta02")
docs("androidx.cursoradapter:cursoradapter:1.0.0")
docs("androidx.customview:customview:1.2.0-alpha02")
docs("androidx.customview:customview-poolingcontainer:1.0.0-rc01")
diff --git a/docs/api_guidelines/compat.md b/docs/api_guidelines/compat.md
index 6ec06be..a86ad2a 100644
--- a/docs/api_guidelines/compat.md
+++ b/docs/api_guidelines/compat.md
@@ -404,43 +404,75 @@
### Inter-process communication {#ipc}
Protocols and data structures used for IPC must support interoperability between
-different versions of libraries and should be treated similarly to public API;
-however, AndroidX does not currently implement compatibility tracking for IPC.
-
-We recommend the following, in order of preference:
-
-1. Stable AIDL if (1) your project lives partially in the Android platform and
- has access to Stable AIDL build rules and (2) you need to support Android's
- `Parcelable` data types. The AndroidX workflow **does not** provide Stable
- AIDL compilation or compatibility checks, so these would need to happen in
- the platform build and the resulting `.java` files would need to be copied
- out.
-2. Protobuf if (1) your project needs to persist data to disk or (2) you need
- interoperability with systems already using Protobuf. Similar to Stable
- AIDL, the AndroidX workflow **does not** provide built-in support Protobuf
- compilation or compatibility checks. It is possible to use a Proto plug-in,
- but you will be responsible for bundling the runtime and maintaining
- compatibility on your own.
-3. `Bundle` if you have a very simple data model that is unlikely to change in
- the future. `Bundle` has the weakest type safety and compatibility
- guarantees of any recommendation, and it has many caveats that make it a
- poor choice.
-4. `VersionedParcelable` if your project is already using Versioned Parcelable
- and is aware of its compatibility constraints.
-
-We are currently evaluating Square's [Wire](https://github.com/square/wire) and
-Google's [gRPC](https://grpc.io/) libraries for recommendation. If either of
-these libraries meets your team's needs based on your own research, feel free to
-use them.
+different versions of libraries and should be treated similarly to public API.
**Do not** design your own serialization mechanism or wire format for disk
storage or inter-process communication. Preserving and verifying compatibility
is difficult and error-prone.
-In all cases, **do not** expose your serialization mechanism in your API
-surface. Neither Stable AIDL nor Protobuf generate stable language APIs.
+**Do not** expose your serialization mechanism in your API surface. Neither
+Stable AIDL nor Protobuf generate stable language APIs.
-#### Annotating unstable IPC
+Generally, any communication prototcol, handshake, etc. must maintain
+compatibility consistent with SemVer guidelines. Consider how your protocol will
+handle addition and removal of operations or constants, compatibility-breaking
+changes, and other modifications without crashing either the host or client
+process.
+
+We recommend the following IPC mechanisms, in order of preference:
+
+#### Stable AIDL <a name="ipc-stableaidl"></a>
+
+Stable AIDL is used by the Android platform and AndroidX to provide a
+platform-native IPC mechanism with strong inter-process compatibility
+guarantees. It supports a subset of standard AIDL.
+
+Use Stable AIDL if your library:
+
+- Needs to send and receive Android's `Parcelable` data types
+- Communicates directly with the Android platform, System UI, or other AOSP
+ components *or* is likely to do so in the future
+
+**Do not** use Stable AIDL to persist data to disk.
+
+##### Using Stable AIDL {#ipc-stableaidl-using}
+
+To add Stable AIDL definitions to your project:
+
+1. Add the Stable AIDL plugin to `build.gradle`:
+
+ ```
+ plugins {
+ id("androidx.stableaidl")
+ }
+ ```
+
+2. Enable the AIDL build feature and specify an initial version for your Stable
+ AIDL interfaces in `build.gradle`:
+
+ ```
+ android {
+ buildFeatures {
+ aidl = true
+ }
+ buildTypes.all {
+ stableAidl {
+ version 1
+ }
+ }
+ }
+ ```
+
+3. Migrate existing AIDL files or create new AIDL files under
+ `<project>/src/main/stableAidl`
+
+4. Generate an initial set of Stable AIDL API tracking files by running
+
+ ```
+ ./gradlew :path:to:project:updateAidlApi
+ ```
+
+##### Annotating unstable AIDL {#ipc-stableaidl-unstable}
Once an API that relies on an IPC contract ships to production in an app, the
contract is locked in and must maintain compatibility to prevent crashing either
@@ -485,25 +517,29 @@
annotations are required for Stable AIDL definition files under
`src/stableAidl`.
-#### Parcelable {#ipc-parcelable}
+#### Protobuf <a name="ipc-protobuf"></a>
-**Do not** implement `Parcelable` for any class that may be used for IPC or
-otherwise exposed as public API. By default, `Parcelable` does not provide any
-compatibility guarantees and will result in crashes if fields are added or
-removed between library versions. If you are using Stable AIDL, you *may* use
-AIDL-defined parcelables for IPC but not public API.
+Protobuf is used by many Google applications and services to provide an IPC and
+disk persistence mechanism with strong inter-process compatibility guarantees.
-NOTE As of 2022/12/16, we are working on experimental support for compiling and
-tracking Stable AIDL definitions within the AndroidX workflow.
+Use Protobuf if your library:
-#### Protobuf {#ipc-protobuf}
+- Communicates directly with other applications or services already using
+ Protobuf
+- Your data structure is complex and likely to change over time - Needs to
+ persist data to disk
-Developers **should** use protocol buffers for most cases. See
-[Protobuf](#dependencies-protobuf) for more information on using protocol
-buffers in your library. **Do** use protocol buffers if your data structure is
-complex and likely to change over time. If your data includes `FileDescriptor`s,
-`Binder`s, or other platform-defined `Parcelable` data structures, they will
-need to be stored alongside the protobuf bytes in a `Bundle`.
+If your data includes `FileDescriptor`s, `Binder`s, or other platform-defined
+`Parcelable` data structures, consider using Stable AIDL instead. Protobuf
+cannot directly handle these types, and they will need to be stored alongside
+the serialized Protobuf bytes in a `Bundle`.
+
+See [Protobuf](#dependencies-protobuf) for more information on using protocol
+buffers in your library.
+
+WARNING While Protobuf is capable of maintaining inter-process compatibility,
+AndroidX does not currently provide compatibility tracking or enforcement.
+Library owners must perform their own validation.
NOTE We are currently investigating the suitability of Square's
[`wire` library](https://github.com/square/wire) for handling protocol buffers
@@ -511,12 +547,24 @@
Libraries that expose their serialization mechanism in their API surface *will
not be able to migrate*.
-#### Bundle {#ipc-bundle}
+#### Bundle <a name="ipc-bundle"></a>
-Developers **may** use `Bundle` in simple cases that require sending `Binder`s,
-`FileDescriptor`s, or platform `Parcelable`s across IPC
-([example](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/graphics/drawable/IconCompat.java;l=820)).
-Note that `Bundle` has several caveats:
+`Bundle` is used by the Android platform and AndroidX as a lightweight IPC
+mechanism. It has the weakest type safety and compatibility guarantees of any
+recommendation, and it has many caveats that make it a poor choice.
+
+In some cases, you may need to use a `Bundle` to wrap another IPC mechanism so
+that it can be passed through Android platform APIs, e.g. a `Bundle` that wraps
+a `byte[]` representing a serialized Protobuf.
+
+Use `Bundle` if your library:
+
+- Has a very simple data model that is unlikely to change in the future
+- Needs to send or receive `Binder`s, `FileDescriptor`s, or platform-defined
+ `Parcelable`s
+ ([example](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/graphics/drawable/IconCompat.java;l=820))
+
+Caveats for `Bundle` include:
- When running on Android S and below, accessing *any* entry in a `Bundle`
will result in the platform attempting to deserialize *every* entry. This
@@ -535,9 +583,39 @@
are responsible for providing their own system for guaranteeing wire format
compatibility between versions.
-#### Communication protocols {#ipc-protocol}
+#### Versioned Parcelable <a name="ipc-versionedparcelable"></a>
-Any communication prototcol, handshake, etc. must maintain compatibility
-consistent with SemVer guidelines. Consider how your protocol will handle
-addition and removal of operations or constants, compatibility-breaking changes,
-and other modifications without crashing either the host or client process.
+`VersionedParcelable` is a deprecated library that was intended to provide
+compatibility guarantees around the Android platform's `Parcelable` class;
+however, the initial version contained bugs and it was not actively maintained.
+
+Use `VersionedParcelable` if your library:
+
+- Is already using `VersionedParcelable` and you are aware of its
+ compatibility constraints
+
+**Do not** use `VersionedParcelable` in all other cases.
+
+#### Wire <a name="ipc-wire"></a>
+
+We are currently evaluating Square's [Wire](https://github.com/square/wire) as a
+front-end to Protobuf. If this library meets your team's needs based on your own
+research, feel free to use it.
+
+#### gRPC <a name="ipc-grpc"></a>
+
+Some clients have requested to use Google's [gRPC](https://grpc.io/) library to
+align with other Google products. It's okay to use gRPC for network
+communication or communication with libraries and services outside of AndroidX
+that are already using gRPC.
+
+**Do not** use gRPC to communicate between AndroidX libraries or with the
+Android platform.
+
+#### Parcelable <a name="ipc-parcelable"></a>
+
+**Do not** implement `Parcelable` for any class that may be used for IPC or
+otherwise exposed as public API. By default, `Parcelable` does not provide any
+compatibility guarantees and will result in crashes if fields are added or
+removed between library versions. If you are using Stable AIDL, you *may* use
+AIDL-defined parcelables for IPC but not public API.
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
index c2dea61..06749ed 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentAnimationTest.kt
@@ -25,6 +25,8 @@
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.view.animation.TranslateAnimation
+import android.window.BackEvent
+import androidx.activity.BackEventCompat
import androidx.annotation.AnimRes
import androidx.annotation.LayoutRes
import androidx.core.view.ViewCompat
@@ -613,6 +615,64 @@
assertThat(fragment1.requireView().parent).isNotNull()
}
+ @Test
+ fun replaceOperationWithAnimationsThenSystemBack() {
+ waitForAnimationReady()
+ val fm1 = activityRule.activity.supportFragmentManager
+
+ val fragment1 = AnimationListenerFragment(R.layout.scene1)
+ fm1.beginTransaction()
+ .replace(R.id.fragmentContainer, fragment1, "1")
+ .addToBackStack(null)
+ .commit()
+ activityRule.waitForExecution()
+
+ val fragment2 = AnimationListenerFragment()
+
+ fm1.beginTransaction()
+ .setCustomAnimations(
+ R.anim.fade_in,
+ R.anim.fade_out,
+ R.anim.fade_in,
+ R.anim.fade_out
+ )
+ .replace(R.id.fragmentContainer, fragment2, "2")
+ .addToBackStack(null)
+ .commit()
+ activityRule.executePendingTransactions(fm1)
+
+ assertThat(fragment2.startAnimationLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ // We need to wait for the exit animation to end
+ assertThat(fragment1.exitLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+
+ val dispatcher = activityRule.activity.onBackPressedDispatcher
+ activityRule.runOnUiThread {
+ dispatcher.dispatchOnBackStarted(BackEventCompat(0.1F, 0.1F, 0.1F, BackEvent.EDGE_LEFT))
+ }
+ activityRule.executePendingTransactions(fm1)
+ activityRule.runOnUiThread {
+ dispatcher.dispatchOnBackProgressed(
+ BackEventCompat(0.2F, 0.2F, 0.2F, BackEvent.EDGE_LEFT)
+ )
+ dispatcher.onBackPressed()
+ }
+ activityRule.executePendingTransactions(fm1)
+
+ assertThat(fragment2.startAnimationLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+ // Now fragment2 should be animating away
+ assertThat(fragment2.isAdded).isFalse()
+ assertThat(fm1.findFragmentByTag("2"))
+ .isEqualTo(null) // fragmentManager does not know about animating fragment
+ assertThat(fragment2.parentFragmentManager)
+ .isEqualTo(fm1) // but the animating fragment knows the fragmentManager
+
+ // We need to wait for the exit animation to end
+ assertThat(fragment2.exitLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+
+ // Make sure the original fragment was correctly readded to the container
+ assertThat(fragment1.requireView().parent).isNotNull()
+ }
+
// When an animation is running on a Fragment's View, the view shouldn't be
// prevented from being removed. There's no way to directly test this, so we have to
// test to see if the animation is still running.
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
index 58a7345..bd08997 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.kt
@@ -767,6 +767,14 @@
}
private class AnimationEffect(val animationInfo: AnimationInfo) : Effect() {
+ override fun onStart(container: ViewGroup) {
+ val operation: Operation = animationInfo.operation
+
+ val finalState = operation.finalState
+ if (finalState !== Operation.State.REMOVED) {
+ operation.effects.add(NoOpEffect(animationInfo))
+ }
+ }
override fun onCommit(container: ViewGroup) {
val context = container.context
val operation: Operation = animationInfo.operation
@@ -780,10 +788,6 @@
// If the operation does not remove the view, we can't use a
// AnimationSet due that causing the introduction of visual artifacts (b/163084315).
viewToAnimate.startAnimation(anim)
- // This means we can't use setAnimationListener() without overriding
- // any listener that the Fragment has set themselves, so we
- // just mark the special effect as complete immediately.
- operation.effects.add(NoOpEffect(animationInfo))
} else {
container.startViewTransition(viewToAnimate)
val animation: Animation = FragmentAnim.EndViewTransitionAnimation(anim,
@@ -968,7 +972,7 @@
"SpecialEffectsController: Container $container has not been " +
"laid out. Completing operation $operation")
}
- operation.effects.add(NoOpEffect(transitionInfo))
+ transitionInfo.completeSpecialEffect()
} else {
transitionImpl.setListenerForTransitionEnd(
transitionInfo.operation.fragment,
diff --git a/glance/glance-appwidget/src/main/AndroidManifest.xml b/glance/glance-appwidget/src/main/AndroidManifest.xml
index ab5123f..3a5868d 100644
--- a/glance/glance-appwidget/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/src/main/AndroidManifest.xml
@@ -19,6 +19,7 @@
<activity
android:name=".action.ActionTrampolineActivity"
android:excludeFromRecents="true"
+ android:theme="@android:style/Theme.NoDisplay"
android:exported="false"
android:enabled="true" />
<activity
diff --git a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampolineActivity.kt b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampolineActivity.kt
index eb0f558..2c32f61 100644
--- a/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampolineActivity.kt
+++ b/glance/glance-appwidget/src/main/java/androidx/glance/appwidget/action/ActionTrampolineActivity.kt
@@ -29,5 +29,6 @@
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
launchTrampolineAction(intent)
+ finish()
}
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index ea26f32..54778a9 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -250,7 +250,7 @@
reactiveStreams = { module = "org.reactivestreams:reactive-streams", version = "1.0.0" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofitConverterWire = { module = "com.squareup.retrofit2:converter-wire", version.ref = "retrofit" }
-robolectric = { module = "org.robolectric:robolectric", version = "4.9.2" }
+robolectric = { module = "org.robolectric:robolectric", version = "4.10.3" }
rxjava2 = { module = "io.reactivex.rxjava2:rxjava", version = "2.2.9" }
rxjava3 = { module = "io.reactivex.rxjava3:rxjava", version = "3.0.0" }
shadow = { module = "gradle.plugin.com.github.johnrengelman:shadow", version = "7.1.1" }
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index e094844..2c9bedec 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -293,6 +293,7 @@
<trusted-key id="90ee19787a7bcf6fd37a1e9180c08b1c29100955">
<trusting group="com.jakewharton.android.repackaged"/>
<trusting group="com.squareup" name="javawriter"/>
+ <trusting group="com.squareup.retrofit2"/>
</trusted-key>
<trusted-key id="95115197c5227c0887299d000f9fe62f88e938d8" group="com.google.dagger"/>
<trusted-key id="98465301a4939c0279f2e847d89d05374952262b" group="org.jetbrains.dokka"/>
diff --git a/health/health-services-client/lint-baseline.xml b/health/health-services-client/lint-baseline.xml
index c9edad9..f42a2d4 100644
--- a/health/health-services-client/lint-baseline.xml
+++ b/health/health-services-client/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-beta02" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0-beta02)" variant="all" version="8.1.0-beta02">
+<issues format="6" by="lint 8.1.0" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0)" variant="all" version="8.1.0">
<issue
id="BanParcelableUsage"
@@ -38,78 +38,6 @@
</issue>
<issue
- id="SyntheticAccessor"
- message="Access to `private` field `mCurrentVersion` of class `Client` requires synthetic accessor"
- errorLine1=" mCurrentVersion ="
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConnectionConfiguration` of class `Client` requires synthetic accessor"
- errorLine1=" return mConnectionConfiguration;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConnectionManager` of class `Client` requires synthetic accessor"
- errorLine1=" mConnectionManager.scheduleForExecution("
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConnectionConfiguration` of class `Client` requires synthetic accessor"
- errorLine1=" new BaseQueueOperation(mConnectionConfiguration));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` field `mConnectionManager` of class `Client` requires synthetic accessor"
- errorLine1=" mConnectionManager.scheduleForExecution("
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `createQueueOperation` of class `Client` requires synthetic accessor"
- errorLine1=" createQueueOperation(operation, settableFuture));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` method `getService` of class `Client` requires synthetic accessor"
- errorLine1=" operation.execute(getService(binder), settableFuture);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/ipc/Client.java"/>
- </issue>
-
- <issue
- id="SyntheticAccessor"
- message="Access to `private` constructor of class `MeasureCallbackStub` requires synthetic accessor"
- errorLine1=" measureCallbackStub = MeasureCallbackStub(callbackKey, measureCallback)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
- <location
- file="src/main/java/androidx/health/services/client/impl/MeasureCallbackStub.kt"/>
- </issue>
-
- <issue
id="LambdaLast"
message="Functional interface parameters (such as parameter 1, "operation", in androidx.health.services.client.impl.ipc.Client.executeWithVersionCheck) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
errorLine1=" RemoteFutureOperation<S, R> operation, int minApiVersion) {"
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseEventCapabilities.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseEventCapabilities.kt
index 87a525c..b71cd76 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseEventCapabilities.kt
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseEventCapabilities.kt
@@ -31,11 +31,11 @@
public companion object {
@JvmStatic
- internal fun fromProto(proto: DataProto.ExerciseEventCapabilities): ExerciseEventCapabilities =
+ internal fun fromProto(proto: DataProto.ExerciseEventCapabilities): ExerciseEventCapabilities? =
when (proto.exerciseEventCapabilitiesCase) {
ExerciseEventCapabilitiesCase.GOLF_SHOT_CAPABILITIES ->
GolfShotEventCapabilities(proto.golfShotCapabilities)
- else -> throw IllegalStateException("Exercise event capabilities not set on $proto")
+ else -> null
}
}
}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseTypeCapabilities.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseTypeCapabilities.kt
index 8f48a02..aa208f6 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseTypeCapabilities.kt
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/ExerciseTypeCapabilities.kt
@@ -71,14 +71,14 @@
supportsAutoPauseAndResume = proto.isAutoPauseAndResumeSupported,
supportedExerciseEvents =
proto.supportedExerciseEventsList
+ .filter { ExerciseEventCapabilities.fromProto(it) != null }
.map { ExerciseEventType.fromProto(it.exerciseEventType) }
.toSet(),
- proto.supportedExerciseEventsList
- .map { entry ->
- ExerciseEventType.fromProto(entry.exerciseEventType) to
- ExerciseEventCapabilities.fromProto(entry)
- }
- .toMap(),
+ exerciseEventCapabilities = proto.supportedExerciseEventsList
+ .filter { ExerciseEventCapabilities.fromProto(it) != null }.associate { entry ->
+ ExerciseEventType.fromProto(entry.exerciseEventType) to
+ ExerciseEventCapabilities.fromProto(entry)!!
+ },
)
internal val proto: DataProto.ExerciseTypeCapabilities =
diff --git a/health/health-services-client/src/test/java/androidx/health/services/client/data/ExerciseTypeCapabilitiesTest.kt b/health/health-services-client/src/test/java/androidx/health/services/client/data/ExerciseTypeCapabilitiesTest.kt
new file mode 100644
index 0000000..80f12ef
--- /dev/null
+++ b/health/health-services-client/src/test/java/androidx/health/services/client/data/ExerciseTypeCapabilitiesTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import androidx.health.services.client.proto.DataProto
+import com.google.common.collect.ImmutableMap
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@RunWith(RobolectricTestRunner::class)
+class ExerciseTypeCapabilitiesTest {
+ @Test
+ fun unknownEventCapabilities_roundTrip_emptyEventCapabilities() {
+ class TestEventCapabilities(override val isSupported: Boolean) :
+ ExerciseEventCapabilities() {
+ override fun toProto(): DataProto.ExerciseEventCapabilities =
+ DataProto.ExerciseEventCapabilities.getDefaultInstance()
+ }
+ val testingCapabilities = ExerciseTypeCapabilities(
+ supportedDataTypes = emptySet(),
+ supportedGoals = emptyMap(),
+ supportedMilestones = emptyMap(),
+ supportsAutoPauseAndResume = true,
+ supportedExerciseEvents = setOf(ExerciseEventType.UNKNOWN),
+ exerciseEventCapabilities =
+ ImmutableMap.of(ExerciseEventType.UNKNOWN,
+ TestEventCapabilities(false)
+ ),
+ )
+
+ val proto = testingCapabilities.proto
+ val capabilitiesReturned = ExerciseTypeCapabilities(proto)
+
+ assertThat(capabilitiesReturned.exerciseEventCapabilities).isEmpty()
+ assertThat(capabilitiesReturned.supportedExerciseEvents).isEmpty()
+ }
+}
diff --git a/hilt/hilt-navigation-fragment/build.gradle b/hilt/hilt-navigation-fragment/build.gradle
index 814229f..95818f4 100644
--- a/hilt/hilt-navigation-fragment/build.gradle
+++ b/hilt/hilt-navigation-fragment/build.gradle
@@ -58,7 +58,7 @@
androidx {
name = "Navigation Fragment Hilt Extension"
publish = Publish.SNAPSHOT_AND_RELEASE
- mavenVersion = LibraryVersions.HILT
+ mavenVersion = LibraryVersions.HILT_NAVIGATION
inceptionYear = "2021"
description = "Android Navigation Fragment Hilt Extension"
}
diff --git a/hilt/hilt-navigation/build.gradle b/hilt/hilt-navigation/build.gradle
index 6539c86..b843758 100644
--- a/hilt/hilt-navigation/build.gradle
+++ b/hilt/hilt-navigation/build.gradle
@@ -34,7 +34,7 @@
androidx {
name = "Navigation Hilt Extension"
publish = Publish.SNAPSHOT_AND_RELEASE
- mavenVersion = LibraryVersions.HILT
+ mavenVersion = LibraryVersions.HILT_NAVIGATION
inceptionYear = "2021"
description = "Android Navigation Hilt Extension"
}
diff --git a/input/input-motionprediction/api/1.0.0-beta03.txt b/input/input-motionprediction/api/1.0.0-beta03.txt
new file mode 100644
index 0000000..b0eef8e
--- /dev/null
+++ b/input/input-motionprediction/api/1.0.0-beta03.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.input.motionprediction {
+
+ public interface MotionEventPredictor {
+ method public static androidx.input.motionprediction.MotionEventPredictor newInstance(android.view.View);
+ method public android.view.MotionEvent? predict();
+ method public void record(android.view.MotionEvent);
+ }
+
+}
+
diff --git a/input/input-motionprediction/api/res-1.0.0-beta03.txt b/input/input-motionprediction/api/res-1.0.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/input/input-motionprediction/api/res-1.0.0-beta03.txt
diff --git a/input/input-motionprediction/api/restricted_1.0.0-beta03.txt b/input/input-motionprediction/api/restricted_1.0.0-beta03.txt
new file mode 100644
index 0000000..b0eef8e
--- /dev/null
+++ b/input/input-motionprediction/api/restricted_1.0.0-beta03.txt
@@ -0,0 +1,11 @@
+// Signature format: 4.0
+package androidx.input.motionprediction {
+
+ public interface MotionEventPredictor {
+ method public static androidx.input.motionprediction.MotionEventPredictor newInstance(android.view.View);
+ method public android.view.MotionEvent? predict();
+ method public void record(android.view.MotionEvent);
+ }
+
+}
+
diff --git a/kruth/kruth/api/api_lint.ignore b/kruth/kruth/api/api_lint.ignore
index 53eae8f..5cce6cd 100644
--- a/kruth/kruth/api/api_lint.ignore
+++ b/kruth/kruth/api/api_lint.ignore
@@ -21,8 +21,8 @@
BuilderSetStyle: androidx.kruth.SimpleSubjectBuilder#that(T):
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.SimpleSubjectBuilder.that(T)
-BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#about(androidx.kruth.Subject.Factory<T,? extends S>):
- Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.about(androidx.kruth.Subject.Factory<T,? extends S>)
+BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#about(androidx.kruth.Subject.Factory<? extends S,T>):
+ Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.about(androidx.kruth.Subject.Factory<? extends S,T>)
BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#fail():
Builder methods names should use setFoo() / addFoo() / clearFoo() style: method androidx.kruth.StandardSubjectBuilder.fail()
BuilderSetStyle: androidx.kruth.StandardSubjectBuilder#that(Boolean):
diff --git a/kruth/kruth/api/current.txt b/kruth/kruth/api/current.txt
index fda56c4..547a8ab 100644
--- a/kruth/kruth/api/current.txt
+++ b/kruth/kruth/api/current.txt
@@ -76,7 +76,7 @@
}
public final class KruthKt {
- method public static <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<T,S> assertAbout(androidx.kruth.Subject.Factory<T,? extends S> subjectFactory);
+ method public static <S extends androidx.kruth.Subject<? extends T>, T> androidx.kruth.SimpleSubjectBuilder<S,T> assertAbout(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
method public static androidx.kruth.BooleanSubject assertThat(Boolean? actual);
method public static androidx.kruth.DoubleSubject assertThat(Double? actual);
method public static <T> androidx.kruth.IterableSubject<T> assertThat(Iterable<? extends T>? actual);
@@ -103,12 +103,12 @@
method public void inOrder();
}
- public final class SimpleSubjectBuilder<T, S extends androidx.kruth.Subject<? extends T>> {
+ public final class SimpleSubjectBuilder<S extends androidx.kruth.Subject<? extends T>, T> {
method public S that(T actual);
}
public final class StandardSubjectBuilder {
- method public <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<T,S> about(androidx.kruth.Subject.Factory<T,? extends S> subjectFactory);
+ method public <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<S,T> about(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
method public Void fail();
method public androidx.kruth.BooleanSubject that(Boolean? actual);
method public androidx.kruth.DoubleSubject that(Double? actual);
@@ -141,6 +141,7 @@
public class Subject<T> {
ctor public Subject(T? actual, optional androidx.kruth.FailureMetadata metadata);
+ method protected final androidx.kruth.StandardSubjectBuilder check();
method protected final Void failWithActual(java.lang.String... messages);
method public final T? getActual();
method public void isAnyOf(Object? first, Object? second, java.lang.Object?... rest);
@@ -158,8 +159,8 @@
property public final T? actual;
}
- public static fun interface Subject.Factory<T, S extends androidx.kruth.Subject<? extends T>> {
- method public S createSubject(androidx.kruth.FailureMetadata metadata, T actual);
+ public static fun interface Subject.Factory<SubjectT extends androidx.kruth.Subject<? extends ActualT>, ActualT> {
+ method public SubjectT createSubject(androidx.kruth.FailureMetadata metadata, ActualT actual);
}
public final class ThrowableSubject<T extends java.lang.Throwable> extends androidx.kruth.Subject<T> {
diff --git a/kruth/kruth/api/restricted_current.txt b/kruth/kruth/api/restricted_current.txt
index 3e7a042..8408566 100644
--- a/kruth/kruth/api/restricted_current.txt
+++ b/kruth/kruth/api/restricted_current.txt
@@ -76,7 +76,7 @@
}
public final class KruthKt {
- method public static <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<T,S> assertAbout(androidx.kruth.Subject.Factory<T,? extends S> subjectFactory);
+ method public static <S extends androidx.kruth.Subject<? extends T>, T> androidx.kruth.SimpleSubjectBuilder<S,T> assertAbout(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
method public static androidx.kruth.BooleanSubject assertThat(Boolean? actual);
method public static androidx.kruth.DoubleSubject assertThat(Double? actual);
method public static <T> androidx.kruth.IterableSubject<T> assertThat(Iterable<? extends T>? actual);
@@ -103,12 +103,12 @@
method public void inOrder();
}
- public final class SimpleSubjectBuilder<T, S extends androidx.kruth.Subject<? extends T>> {
+ public final class SimpleSubjectBuilder<S extends androidx.kruth.Subject<? extends T>, T> {
method public S that(T actual);
}
public final class StandardSubjectBuilder {
- method public <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<T,S> about(androidx.kruth.Subject.Factory<T,? extends S> subjectFactory);
+ method public <T, S extends androidx.kruth.Subject<? extends T>> androidx.kruth.SimpleSubjectBuilder<S,T> about(androidx.kruth.Subject.Factory<? extends S,T> subjectFactory);
method public Void fail();
method public androidx.kruth.BooleanSubject that(Boolean? actual);
method public androidx.kruth.DoubleSubject that(Double? actual);
@@ -141,6 +141,7 @@
public class Subject<T> {
ctor public Subject(T? actual, optional androidx.kruth.FailureMetadata metadata);
+ method protected final androidx.kruth.StandardSubjectBuilder check();
method @kotlin.PublishedApi internal final void doFail(String message);
method protected final Void failWithActual(java.lang.String... messages);
method public final T? getActual();
@@ -159,8 +160,8 @@
property public final T? actual;
}
- public static fun interface Subject.Factory<T, S extends androidx.kruth.Subject<? extends T>> {
- method public S createSubject(androidx.kruth.FailureMetadata metadata, T actual);
+ public static fun interface Subject.Factory<SubjectT extends androidx.kruth.Subject<? extends ActualT>, ActualT> {
+ method public SubjectT createSubject(androidx.kruth.FailureMetadata metadata, ActualT actual);
}
public final class ThrowableSubject<T extends java.lang.Throwable> extends androidx.kruth.Subject<T> {
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt
index e45f3b5..94b79f1 100644
--- a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Kruth.kt
@@ -62,7 +62,7 @@
* Given a factory for some [Subject] class, returns [SimpleSubjectBuilder] whose
* [that][SimpleSubjectBuilder.that] method creates instances of that class.
*/
-fun <T, S : Subject<T>> assertAbout(
- subjectFactory: Subject.Factory<T, S>,
-): SimpleSubjectBuilder<T, S> =
+fun <S : Subject<T>, T> assertAbout(
+ subjectFactory: Subject.Factory<S, T>,
+): SimpleSubjectBuilder<S, T> =
SimpleSubjectBuilder(subjectFactory = subjectFactory)
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/SimpleSubjectBuilder.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/SimpleSubjectBuilder.kt
index a336739..6f817d2 100644
--- a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/SimpleSubjectBuilder.kt
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/SimpleSubjectBuilder.kt
@@ -29,9 +29,9 @@
* [our doc on extensions](https://truth.dev/extension). It explains where [Subject.Factory] fits
* into the process.
*/
-class SimpleSubjectBuilder<T, out S : Subject<T>> internal constructor(
+class SimpleSubjectBuilder<out S : Subject<T>, T> internal constructor(
private val metadata: FailureMetadata = FailureMetadata(),
- private val subjectFactory: Subject.Factory<T, S>,
+ private val subjectFactory: Subject.Factory<S, T>,
) {
fun that(actual: T): S =
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt
index 62fca97..dbc50ef 100644
--- a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/StandardSubjectBuilder.kt
@@ -65,8 +65,8 @@
* use the previously set failure strategy and any previously set failure message.
*/
fun <T, S : Subject<T>> about(
- subjectFactory: Subject.Factory<T, S>,
- ): SimpleSubjectBuilder<T, S> =
+ subjectFactory: Subject.Factory<S, T>,
+ ): SimpleSubjectBuilder<S, T> =
SimpleSubjectBuilder(metadata = metadata, subjectFactory = subjectFactory)
/**
diff --git a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Subject.kt b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Subject.kt
index 76c5ae1b..304f023 100644
--- a/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Subject.kt
+++ b/kruth/kruth/src/commonMain/kotlin/androidx/kruth/Subject.kt
@@ -33,6 +33,8 @@
private val metadata: FailureMetadata = FailureMetadata(),
) {
+ protected fun check(): StandardSubjectBuilder = StandardSubjectBuilder(metadata = metadata)
+
internal val asserter: KruthAsserter get() = asserter()
internal fun asserter(withActual: Boolean = false): KruthAsserter =
@@ -252,7 +254,7 @@
* [our doc on extensions](https://truth.dev/extension). It explains where [Factory] fits into
* the process.
*/
- fun interface Factory<T, out S : Subject<T>> {
- fun createSubject(metadata: FailureMetadata, actual: T): S
+ fun interface Factory<out SubjectT : Subject<ActualT>, ActualT> {
+ fun createSubject(metadata: FailureMetadata, actual: ActualT): SubjectT
}
}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/ChainingTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/ChainingTest.kt
new file mode 100644
index 0000000..661ab55
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/ChainingTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.kruth
+
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class ChainingTest {
+ @Test
+ fun singleChain() {
+ assertFailsWith<AssertionError> {
+ ObjectSubject.assertThat("object1").isNotAnObject()
+ }
+ }
+
+ @Test
+ fun doubleChain() {
+ assertFailsWith<AssertionError> {
+ ObjectSubject.assertThat("object1")
+ .chain("object2")
+ .isNotAnObject()
+ }
+ }
+
+ @Test
+ fun tripleChain() {
+ assertFailsWith<AssertionError> {
+ ObjectSubject.assertThat("object1")
+ .chain("object2")
+ .chain("object3")
+ .isNotAnObject()
+ }
+ }
+
+ private class ObjectSubject(
+ metadata: FailureMetadata = FailureMetadata(),
+ actual: Any?,
+ ) : Subject<Any>(actual = actual, metadata = metadata) {
+ companion object {
+ val FACTORY: Factory<ObjectSubject, Any> = Factory<ObjectSubject, Any> {
+ metadata, actual -> ObjectSubject(metadata, actual)
+ }
+
+ // entry point
+ fun assertThat(obj: Any): ObjectSubject {
+ return assertAbout(::ObjectSubject).that(obj)
+ }
+ }
+
+ fun isNotAnObject() {
+ asserter.fail("Expected be an Object.")
+ }
+
+ fun chain(actual: Any): ObjectSubject {
+ return check().about(ObjectSubject.FACTORY).that(actual)
+ }
+ }
+}
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/Employee.kt
similarity index 61%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/Employee.kt
index 31d0e6f..038269a 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/Employee.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,19 @@
* limitations under the License.
*/
-package androidx.lifecycle.observers;
+package androidx.kruth.extension
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
- @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
+/**
+ * Example custom subject class.
+ */
+class Employee(
+ val username: String,
+ val id: String,
+ val name: String,
+ val location: Location,
+ val isCeo: Boolean,
+) {
+ enum class Location {
+ MTV, PIT, CHI, NYC
+ }
}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/EmployeeSubject.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/EmployeeSubject.kt
new file mode 100644
index 0000000..4e25fc6
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/EmployeeSubject.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.kruth.extension
+
+import androidx.kruth.ComparableSubject
+import androidx.kruth.FailureMetadata
+import androidx.kruth.StringSubject
+import androidx.kruth.Subject
+import androidx.kruth.assertAbout
+import androidx.kruth.requireNonNull
+
+class EmployeeSubject(
+ metadata: FailureMetadata = FailureMetadata(),
+ actual: Employee?,
+) : Subject<Employee>(actual = actual, metadata = metadata) {
+
+ companion object {
+ // User-defined entry point
+ fun assertThat(employee: Employee): EmployeeSubject {
+ return assertAbout(::EmployeeSubject).that(employee)
+ }
+ }
+
+ // User-defined test assertion SPI below this point
+ fun hasName(name: String) {
+ requireNonNull(actual) { "Expected to have a $name, but was null" }
+ name().isEqualTo(name)
+ }
+
+ fun hasUsername(username: String) {
+ requireNonNull(actual) { "Expected to have a $username, but was null" }
+ username().isEqualTo(username)
+ }
+
+ fun hasId(id: String) {
+ requireNonNull(actual) { "Expected to have an $id, but was null" }
+ id().isEqualTo(id)
+ }
+
+ fun hasLocation(location: Employee.Location) {
+ requireNonNull(actual) { "Expected to have a $location, but was null" }
+ location().isEqualTo(location)
+ }
+
+ fun isCeo() {
+ requireNonNull(actual) { "Expected to be CEO, but was null" }
+ if (!actual!!.isCeo) {
+ asserter.fail("Expected to be CEO")
+ }
+ }
+
+ fun isNotCeo() {
+ requireNonNull(actual) { "Expected to not be CEO, but was null" }
+ if (actual!!.isCeo) {
+ asserter.fail("Expected to not be CEO")
+ }
+ }
+
+ // Chained subjects methods below this point
+ private fun name(): StringSubject {
+ return check().that(actual?.name)
+ }
+
+ private fun username(): StringSubject {
+ return check().that(actual?.username)
+ }
+
+ private fun id(): StringSubject {
+ return check().that(actual?.id)
+ }
+
+ private fun location(): ComparableSubject<Employee.Location> {
+ return check().that(actual?.location)
+ }
+}
diff --git a/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/EmployeeSubjectTest.kt b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/EmployeeSubjectTest.kt
new file mode 100644
index 0000000..38a6016
--- /dev/null
+++ b/kruth/kruth/src/commonTest/kotlin/androidx/kruth/extension/EmployeeSubjectTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.kruth.extension
+
+import androidx.kruth.extension.Employee.Location
+import androidx.kruth.extension.EmployeeSubject.Companion.assertThat
+import kotlin.test.Test
+import kotlin.test.assertFailsWith
+
+class EmployeeSubjectTest {
+
+ private val employee = Employee("jdoe", "37802", "John Doe", Location.NYC, false)
+
+ @Test
+ fun usernameEquals() {
+ assertThat(employee).hasUsername("jdoe")
+ }
+
+ @Test
+ fun idEquals() {
+ assertThat(employee).hasId("37802")
+ }
+
+ @Test
+ fun nameEquals() {
+ assertThat(employee).hasName("John Doe")
+ }
+
+ @Test
+ fun locationEqualsPasses() {
+ assertThat(employee).hasLocation(Location.NYC)
+ }
+
+ @Test
+ fun locationEqualsFails() {
+ assertFailsWith<AssertionError> {
+ assertThat(employee).hasLocation(Location.MTV)
+ }
+ }
+
+ @Test
+ fun isCeoFalsePasses() {
+ assertThat(employee).isNotCeo()
+ }
+
+ @Test
+ fun isCeoTrueFails() {
+ assertFailsWith<AssertionError> {
+ assertThat(employee).isCeo()
+ }
+ }
+}
diff --git a/libraryversions.toml b/libraryversions.toml
index 0bd6831..9c45f40 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -1,49 +1,49 @@
[versions]
ACTIVITY = "1.8.0-alpha06"
-ANNOTATION = "1.7.0-alpha03"
+ANNOTATION = "1.7.0-beta01"
ANNOTATION_EXPERIMENTAL = "1.4.0-alpha01"
APPACTIONS_BUILTINTYPES = "1.0.0-alpha01"
APPACTIONS_INTERACTION = "1.0.0-alpha01"
-APPCOMPAT = "1.7.0-alpha03"
+APPCOMPAT = "1.7.0-alpha04"
APPSEARCH = "1.1.0-alpha04"
ARCH_CORE = "2.3.0-alpha01"
ASYNCLAYOUTINFLATER = "1.1.0-alpha02"
AUTOFILL = "1.3.0-alpha02"
-BENCHMARK = "1.2.0-beta02"
+BENCHMARK = "1.2.0-beta03"
BIOMETRIC = "1.2.0-alpha06"
BLUETOOTH = "1.0.0-alpha01"
-BROWSER = "1.6.0-rc01"
+BROWSER = "1.7.0-alpha01"
BUILDSRC_TESTS = "1.0.0-alpha01"
-CAMERA = "1.3.0-beta02"
+CAMERA = "1.3.0-beta03"
CAMERA_PIPE = "1.0.0-alpha01"
CARDVIEW = "1.1.0-alpha01"
-CAR_APP = "1.4.0-alpha02"
-COLLECTION = "1.3.0-alpha05"
-COMPOSE = "1.6.0-alpha02"
+CAR_APP = "1.4.0-beta01"
+COLLECTION = "1.3.0-beta01"
+COMPOSE = "1.6.0-alpha03"
COMPOSE_COMPILER = "1.5.1"
-COMPOSE_MATERIAL3 = "1.2.0-alpha04"
+COMPOSE_MATERIAL3 = "1.2.0-alpha05"
COMPOSE_MATERIAL3_ADAPTIVE = "1.0.0-alpha01"
COMPOSE_RUNTIME_TRACING = "1.0.0-alpha03"
-CONSTRAINTLAYOUT = "2.2.0-alpha11"
-CONSTRAINTLAYOUT_COMPOSE = "1.1.0-alpha11"
-CONSTRAINTLAYOUT_CORE = "1.1.0-alpha11"
+CONSTRAINTLAYOUT = "2.2.0-alpha12"
+CONSTRAINTLAYOUT_COMPOSE = "1.1.0-alpha12"
+CONSTRAINTLAYOUT_CORE = "1.1.0-alpha12"
CONTENTPAGER = "1.1.0-alpha01"
COORDINATORLAYOUT = "1.3.0-alpha01"
-CORE = "1.12.0-beta01"
+CORE = "1.12.0-rc01"
CORE_ANIMATION = "1.0.0-rc01"
CORE_ANIMATION_TESTING = "1.0.0-rc01"
CORE_APPDIGEST = "1.0.0-alpha01"
-CORE_GOOGLE_SHORTCUTS = "1.2.0-alpha01"
+CORE_GOOGLE_SHORTCUTS = "1.2.0-alpha02"
CORE_HAPTICS = "1.0.0-alpha01"
-CORE_I18N = "1.0.0-alpha01"
-CORE_LOCATION_ALTITUDE = "1.0.0-alpha01"
+CORE_I18N = "1.0.0-alpha02"
+CORE_LOCATION_ALTITUDE = "1.0.0-alpha02"
CORE_PERFORMANCE = "1.0.0-alpha03"
-CORE_REMOTEVIEWS = "1.0.0-rc01"
+CORE_REMOTEVIEWS = "1.1.0-alpha01"
CORE_ROLE = "1.2.0-alpha01"
CORE_SPLASHSCREEN = "1.1.0-alpha01"
CORE_TELECOM = "1.0.0-alpha01"
-CORE_UWB = "1.0.0-alpha06"
-CREDENTIALS = "1.2.0-beta01"
+CORE_UWB = "1.0.0-alpha07"
+CREDENTIALS = "1.2.0-beta02"
CURSORADAPTER = "1.1.0-alpha01"
CUSTOMVIEW = "1.2.0-alpha03"
CUSTOMVIEW_POOLINGCONTAINER = "1.1.0-alpha01"
@@ -54,7 +54,7 @@
DYNAMICANIMATION = "1.1.0-alpha04"
DYNAMICANIMATION_KTX = "1.0.0-alpha04"
EMOJI = "1.2.0-alpha03"
-EMOJI2 = "1.4.0-rc01"
+EMOJI2 = "1.5.0-alpha01"
ENTERPRISE = "1.1.0-rc01"
EXIFINTERFACE = "1.4.0-alpha01"
FRAGMENT = "1.7.0-alpha02"
@@ -64,16 +64,17 @@
GLANCE_TEMPLATE = "1.0.0-alpha06"
GLANCE_WEAR_TILES = "1.0.0-alpha06"
GRAPHICS_CORE = "1.0.0-alpha04"
-GRAPHICS_PATH = "1.0.0-alpha02"
GRAPHICS_FILTERS = "1.0.0-alpha01"
+GRAPHICS_PATH = "1.0.0-alpha02"
GRAPHICS_SHAPES = "1.0.0-alpha03"
GRIDLAYOUT = "1.1.0-beta02"
-HEALTH_CONNECT = "1.1.0-alpha03"
+HEALTH_CONNECT = "1.1.0-alpha04"
HEALTH_SERVICES_CLIENT = "1.1.0-alpha01"
-HEIFWRITER = "1.1.0-alpha02"
-HILT = "1.1.0-alpha03"
+HEIFWRITER = "1.1.0-alpha03"
+HILT = "1.1.0-alpha01"
+HILT_NAVIGATION = "1.1.0-alpha03"
HILT_NAVIGATION_COMPOSE = "1.1.0-alpha02"
-INPUT_MOTIONPREDICTION = "1.0.0-beta02"
+INPUT_MOTIONPREDICTION = "1.0.0-beta03"
INSPECTION = "1.0.0"
INTERPOLATOR = "1.1.0-alpha01"
JAVASCRIPTENGINE = "1.0.0-alpha06"
@@ -85,14 +86,14 @@
LEANBACK_TAB = "1.1.0-beta01"
LEGACY = "1.1.0-alpha01"
LIBYUV = "0.1.0-dev01"
-LIFECYCLE = "2.7.0-alpha01"
+LIFECYCLE = "2.7.0-alpha02"
LIFECYCLE_EXTENSIONS = "2.2.0"
LOADER = "1.2.0-alpha01"
-MEDIA = "1.7.0-alpha02"
+MEDIA = "1.7.0-beta01"
MEDIA2 = "1.3.0-alpha01"
MEDIAROUTER = "1.6.0-beta01"
METRICS = "1.0.0-alpha05"
-NAVIGATION = "2.7.0-rc01"
+NAVIGATION = "2.8.0-alpha01"
PAGING = "3.3.0-alpha01"
PALETTE = "1.1.0-alpha01"
PERCENTLAYOUT = "1.1.0-alpha01"
@@ -100,9 +101,9 @@
PRINT = "1.1.0-beta01"
PRIVACYSANDBOX_ADS = "1.1.0-alpha01"
PRIVACYSANDBOX_PLUGINS = "1.0.0-alpha02"
-PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha07"
+PRIVACYSANDBOX_SDKRUNTIME = "1.0.0-alpha08"
PRIVACYSANDBOX_TOOLS = "1.0.0-alpha05"
-PRIVACYSANDBOX_UI = "1.0.0-alpha04"
+PRIVACYSANDBOX_UI = "1.0.0-alpha05"
PROFILEINSTALLER = "1.4.0-alpha01"
RECOMMENDATION = "1.1.0-alpha01"
RECYCLERVIEW = "1.4.0-alpha01"
@@ -130,12 +131,12 @@
SWIPEREFRESHLAYOUT = "1.2.0-alpha01"
TESTEXT = "1.0.0-alpha02"
TESTSCREENSHOT = "1.0.0-alpha01"
-TEST_UIAUTOMATOR = "2.3.0-alpha04"
+TEST_UIAUTOMATOR = "2.3.0-alpha05"
TEXT = "1.0.0-alpha01"
TRACING = "1.3.0-alpha02"
TRACING_PERFETTO = "1.0.0-beta01"
TRANSITION = "1.5.0-alpha01"
-TV = "1.0.0-alpha08"
+TV = "1.0.0-alpha09"
TVPROVIDER = "1.1.0-alpha02"
VECTORDRAWABLE = "1.2.0-rc01"
VECTORDRAWABLE_ANIMATED = "1.2.0-rc01"
@@ -144,22 +145,22 @@
VIEWPAGER = "1.1.0-alpha02"
VIEWPAGER2 = "1.1.0-beta03"
WEAR = "1.3.0-rc01"
-WEAR_COMPOSE = "1.3.0-alpha02"
-WEAR_COMPOSE_MATERIAL3 = "1.0.0-alpha08"
+WEAR_COMPOSE = "1.3.0-alpha03"
+WEAR_COMPOSE_MATERIAL3 = "1.0.0-alpha09"
WEAR_INPUT = "1.2.0-alpha03"
WEAR_INPUT_TESTING = "1.2.0-alpha03"
WEAR_ONGOING = "1.1.0-alpha01"
WEAR_PHONE_INTERACTIONS = "1.1.0-alpha04"
-WEAR_PROTOLAYOUT = "1.0.0-rc01"
+WEAR_PROTOLAYOUT = "1.1.0-alpha01"
WEAR_REMOTE_INTERACTIONS = "1.1.0-alpha01"
-WEAR_TILES = "1.2.0-rc01"
+WEAR_TILES = "1.3.0-alpha01"
WEAR_WATCHFACE = "1.2.0-alpha09"
-WEBKIT = "1.8.0-beta01"
-WINDOW = "1.2.0-beta01"
+WEBKIT = "1.8.0-rc01"
+WINDOW = "1.2.0-beta02"
WINDOW_EXTENSIONS = "1.2.0-rc01"
WINDOW_EXTENSIONS_CORE = "1.1.0-alpha01"
WINDOW_SIDECAR = "1.0.0-rc01"
-WORK = "2.9.0-alpha02"
+WORK = "2.9.0-alpha03"
[groups]
ACTIVITY = { group = "androidx.activity", atomicGroupVersion = "versions.ACTIVITY" }
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.java
deleted file mode 100644
index ac0474a..0000000
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 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.lifecycle.observers;
-
-import androidx.lifecycle.Lifecycle;
-
-@SuppressWarnings("deprecation")
-public class DerivedWithOverriddenMethodsWithLfAnnotation extends Base {
-
- @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- @Override
- public void onCreate() {
- super.onCreate();
- }
-}
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.kt
similarity index 74%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.kt
index 31d0e6f..f239dfc 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/DerivedWithOverriddenMethodsWithLfAnnotation.kt
@@ -13,15 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package androidx.lifecycle.observers
-package androidx.lifecycle.observers;
+import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
+@Suppress("DEPRECATION")
+class DerivedWithOverriddenMethodsWithLfAnnotation : Base() {
@androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
+ override fun onCreate() {
+ super.onCreate()
+ }
}
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.kt
similarity index 74%
rename from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
rename to lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.kt
index 31d0e6f..fb49485 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.kt
@@ -13,15 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package androidx.lifecycle.observers
-package androidx.lifecycle.observers;
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
+@Suppress("DEPRECATION")
+interface Interface1 : LifecycleObserver {
@androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
+ fun onCreate()
}
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.java b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.kt
similarity index 74%
rename from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.java
rename to lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.kt
index f272601..b3faa538a 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.java
+++ b/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface2.kt
@@ -13,18 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package androidx.lifecycle.observers
-package androidx.lifecycle.observers;
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface2 extends LifecycleObserver {
-
+@Suppress("DEPRECATION")
+interface Interface2 : LifecycleObserver {
@androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
+ fun onCreate()
@androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
- void onDestroy();
+ fun onDestroy()
}
diff --git a/media/media/api/1.7.0-beta01.txt b/media/media/api/1.7.0-beta01.txt
new file mode 100644
index 0000000..2509d03
--- /dev/null
+++ b/media/media/api/1.7.0-beta01.txt
@@ -0,0 +1,766 @@
+// Signature format: 4.0
+package android.support.v4.media {
+
+ public final class MediaBrowserCompat {
+ ctor public MediaBrowserCompat(android.content.Context!, android.content.ComponentName!, android.support.v4.media.MediaBrowserCompat.ConnectionCallback!, android.os.Bundle!);
+ method public void connect();
+ method public void disconnect();
+ method public android.os.Bundle? getExtras();
+ method public void getItem(String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+ method public String getRoot();
+ method public android.content.ComponentName getServiceComponent();
+ method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+ method public boolean isConnected();
+ method public void search(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.SearchCallback);
+ method public void sendCustomAction(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.CustomActionCallback?);
+ method public void subscribe(String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+ method public void subscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+ method public void unsubscribe(String);
+ method public void unsubscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+ field public static final String CUSTOM_ACTION_DOWNLOAD = "android.support.v4.media.action.DOWNLOAD";
+ field public static final String CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE = "android.support.v4.media.action.REMOVE_DOWNLOADED_FILE";
+ field public static final String EXTRA_DOWNLOAD_PROGRESS = "android.media.browse.extra.DOWNLOAD_PROGRESS";
+ field public static final String EXTRA_MEDIA_ID = "android.media.browse.extra.MEDIA_ID";
+ field public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+ field public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+ }
+
+ public static class MediaBrowserCompat.ConnectionCallback {
+ ctor public MediaBrowserCompat.ConnectionCallback();
+ method public void onConnected();
+ method public void onConnectionFailed();
+ method public void onConnectionSuspended();
+ }
+
+ public abstract static class MediaBrowserCompat.CustomActionCallback {
+ ctor public MediaBrowserCompat.CustomActionCallback();
+ method public void onError(String!, android.os.Bundle!, android.os.Bundle!);
+ method public void onProgressUpdate(String!, android.os.Bundle!, android.os.Bundle!);
+ method public void onResult(String!, android.os.Bundle!, android.os.Bundle!);
+ }
+
+ public abstract static class MediaBrowserCompat.ItemCallback {
+ ctor public MediaBrowserCompat.ItemCallback();
+ method public void onError(String);
+ method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem!);
+ }
+
+ public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+ ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+ method public int describeContents();
+ method public static android.support.v4.media.MediaBrowserCompat.MediaItem! fromMediaItem(Object!);
+ method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>! fromMediaItemList(java.util.List<?>!);
+ method public android.support.v4.media.MediaDescriptionCompat getDescription();
+ method public int getFlags();
+ method public String? getMediaId();
+ method public boolean isBrowsable();
+ method public boolean isPlayable();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem!>! CREATOR;
+ field public static final int FLAG_BROWSABLE = 1; // 0x1
+ field public static final int FLAG_PLAYABLE = 2; // 0x2
+ }
+
+ public abstract static class MediaBrowserCompat.SearchCallback {
+ ctor public MediaBrowserCompat.SearchCallback();
+ method public void onError(String, android.os.Bundle!);
+ method public void onSearchResult(String, android.os.Bundle!, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+ }
+
+ public abstract static class MediaBrowserCompat.SubscriptionCallback {
+ ctor public MediaBrowserCompat.SubscriptionCallback();
+ method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+ method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>, android.os.Bundle);
+ method public void onError(String);
+ method public void onError(String, android.os.Bundle);
+ }
+
+ public final class MediaDescriptionCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.MediaDescriptionCompat! fromMediaDescription(Object!);
+ method public CharSequence? getDescription();
+ method public android.os.Bundle? getExtras();
+ method public android.graphics.Bitmap? getIconBitmap();
+ method public android.net.Uri? getIconUri();
+ method public Object! getMediaDescription();
+ method public String? getMediaId();
+ method public android.net.Uri? getMediaUri();
+ method public CharSequence? getSubtitle();
+ method public CharSequence? getTitle();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+ field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+ field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+ field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+ field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+ field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+ field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat!>! CREATOR;
+ field public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+ field public static final String EXTRA_DOWNLOAD_STATUS = "android.media.extra.DOWNLOAD_STATUS";
+ field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
+ field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
+ field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
+ }
+
+ public static final class MediaDescriptionCompat.Builder {
+ ctor public MediaDescriptionCompat.Builder();
+ method public android.support.v4.media.MediaDescriptionCompat! build();
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setDescription(CharSequence?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setExtras(android.os.Bundle?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconBitmap(android.graphics.Bitmap?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconUri(android.net.Uri?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaId(String?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaUri(android.net.Uri?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setSubtitle(CharSequence?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setTitle(CharSequence?);
+ }
+
+ public final class MediaMetadataCompat implements android.os.Parcelable {
+ method public boolean containsKey(String!);
+ method public int describeContents();
+ method public static android.support.v4.media.MediaMetadataCompat! fromMediaMetadata(Object!);
+ method public android.graphics.Bitmap! getBitmap(String!);
+ method public android.os.Bundle! getBundle();
+ method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+ method public long getLong(String!);
+ method public Object! getMediaMetadata();
+ method public android.support.v4.media.RatingCompat! getRating(String!);
+ method public String! getString(String!);
+ method public CharSequence! getText(String!);
+ method public java.util.Set<java.lang.String!>! keySet();
+ method public int size();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat!>! CREATOR;
+ field public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+ field public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+ field public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+ field public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+ field public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+ field public static final String METADATA_KEY_ART = "android.media.metadata.ART";
+ field public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+ field public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+ field public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+ field public static final String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+ field public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+ field public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+ field public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
+ field public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+ field public static final String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+ field public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+ field public static final String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+ field public static final String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+ field public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+ field public static final String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
+ field public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+ field public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+ field public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+ field public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+ field public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+ field public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
+ field public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+ field public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+ field public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+ field public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+ field public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+ }
+
+ public static final class MediaMetadataCompat.Builder {
+ ctor public MediaMetadataCompat.Builder();
+ ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat!);
+ method public android.support.v4.media.MediaMetadataCompat! build();
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putBitmap(String!, android.graphics.Bitmap!);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putLong(String!, long);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putRating(String!, android.support.v4.media.RatingCompat!);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putString(String!, String!);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putText(String!, CharSequence!);
+ }
+
+ public final class RatingCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.RatingCompat! fromRating(Object!);
+ method public float getPercentRating();
+ method public Object! getRating();
+ method public int getRatingStyle();
+ method public float getStarRating();
+ method public boolean hasHeart();
+ method public boolean isRated();
+ method public boolean isThumbUp();
+ method public static android.support.v4.media.RatingCompat! newHeartRating(boolean);
+ method public static android.support.v4.media.RatingCompat! newPercentageRating(float);
+ method public static android.support.v4.media.RatingCompat! newStarRating(int, float);
+ method public static android.support.v4.media.RatingCompat! newThumbRating(boolean);
+ method public static android.support.v4.media.RatingCompat! newUnratedRating(int);
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat!>! CREATOR;
+ field public static final int RATING_3_STARS = 3; // 0x3
+ field public static final int RATING_4_STARS = 4; // 0x4
+ field public static final int RATING_5_STARS = 5; // 0x5
+ field public static final int RATING_HEART = 1; // 0x1
+ field public static final int RATING_NONE = 0; // 0x0
+ field public static final int RATING_PERCENTAGE = 6; // 0x6
+ field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+ }
+
+}
+
+package android.support.v4.media.session {
+
+ public final class MediaControllerCompat {
+ ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat);
+ ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat.Token);
+ method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+ method public void adjustVolume(int, int);
+ method public boolean dispatchMediaButtonEvent(android.view.KeyEvent!);
+ method public android.os.Bundle! getExtras();
+ method public long getFlags();
+ method public Object! getMediaController();
+ method public static android.support.v4.media.session.MediaControllerCompat! getMediaController(android.app.Activity);
+ method public android.support.v4.media.MediaMetadataCompat! getMetadata();
+ method public String! getPackageName();
+ method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo! getPlaybackInfo();
+ method public android.support.v4.media.session.PlaybackStateCompat! getPlaybackState();
+ method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! getQueue();
+ method public CharSequence! getQueueTitle();
+ method public int getRatingType();
+ method public int getRepeatMode();
+ method public android.app.PendingIntent! getSessionActivity();
+ method public android.os.Bundle getSessionInfo();
+ method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+ method public int getShuffleMode();
+ method public android.support.v4.media.session.MediaControllerCompat.TransportControls! getTransportControls();
+ method public boolean isCaptioningEnabled();
+ method public boolean isSessionReady();
+ method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+ method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler!);
+ method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method @Deprecated public void removeQueueItemAt(int);
+ method public void sendCommand(String, android.os.Bundle?, android.os.ResultReceiver?);
+ method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat!);
+ method public void setVolumeTo(int, int);
+ method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+ }
+
+ public abstract static class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+ ctor public MediaControllerCompat.Callback();
+ method public void binderDied();
+ method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo!);
+ method public void onCaptioningEnabledChanged(boolean);
+ method public void onExtrasChanged(android.os.Bundle!);
+ method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat!);
+ method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat!);
+ method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+ method public void onQueueTitleChanged(CharSequence!);
+ method public void onRepeatModeChanged(int);
+ method public void onSessionDestroyed();
+ method public void onSessionEvent(String!, android.os.Bundle!);
+ method public void onSessionReady();
+ method public void onShuffleModeChanged(int);
+ }
+
+ public static final class MediaControllerCompat.PlaybackInfo {
+ method public androidx.media.AudioAttributesCompat getAudioAttributes();
+ method @Deprecated public int getAudioStream();
+ method public int getCurrentVolume();
+ method public int getMaxVolume();
+ method public int getPlaybackType();
+ method public int getVolumeControl();
+ field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+ field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+ }
+
+ public abstract static class MediaControllerCompat.TransportControls {
+ method public abstract void fastForward();
+ method public abstract void pause();
+ method public abstract void play();
+ method public abstract void playFromMediaId(String!, android.os.Bundle!);
+ method public abstract void playFromSearch(String!, android.os.Bundle!);
+ method public abstract void playFromUri(android.net.Uri!, android.os.Bundle!);
+ method public abstract void prepare();
+ method public abstract void prepareFromMediaId(String!, android.os.Bundle!);
+ method public abstract void prepareFromSearch(String!, android.os.Bundle!);
+ method public abstract void prepareFromUri(android.net.Uri!, android.os.Bundle!);
+ method public abstract void rewind();
+ method public abstract void seekTo(long);
+ method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!, android.os.Bundle!);
+ method public abstract void sendCustomAction(String!, android.os.Bundle!);
+ method public abstract void setCaptioningEnabled(boolean);
+ method public void setPlaybackSpeed(float);
+ method public abstract void setRating(android.support.v4.media.RatingCompat!);
+ method public abstract void setRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+ method public abstract void setRepeatMode(int);
+ method public abstract void setShuffleMode(int);
+ method public abstract void skipToNext();
+ method public abstract void skipToPrevious();
+ method public abstract void skipToQueueItem(long);
+ method public abstract void stop();
+ field @Deprecated public static final String EXTRA_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+ }
+
+ public class MediaSessionCompat {
+ ctor public MediaSessionCompat(android.content.Context, String);
+ ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?);
+ ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?, android.os.Bundle?);
+ method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+ method public static android.support.v4.media.session.MediaSessionCompat! fromMediaSession(android.content.Context!, Object!);
+ method public android.support.v4.media.session.MediaControllerCompat! getController();
+ method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
+ method public Object! getMediaSession();
+ method public Object! getRemoteControlClient();
+ method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+ method public boolean isActive();
+ method public void release();
+ method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+ method public void sendSessionEvent(String!, android.os.Bundle!);
+ method public void setActive(boolean);
+ method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!);
+ method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!, android.os.Handler!);
+ method public void setCaptioningEnabled(boolean);
+ method public void setExtras(android.os.Bundle!);
+ method public void setFlags(int);
+ method public void setMediaButtonReceiver(android.app.PendingIntent!);
+ method public void setMetadata(android.support.v4.media.MediaMetadataCompat!);
+ method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat!);
+ method public void setPlaybackToLocal(int);
+ method public void setPlaybackToRemote(androidx.media.VolumeProviderCompat!);
+ method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+ method public void setQueueTitle(CharSequence!);
+ method public void setRatingType(int);
+ method public void setRepeatMode(int);
+ method public void setSessionActivity(android.app.PendingIntent!);
+ method public void setShuffleMode(int);
+ field public static final String ACTION_FLAG_AS_INAPPROPRIATE = "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
+ field public static final String ACTION_FOLLOW = "android.support.v4.media.session.action.FOLLOW";
+ field public static final String ACTION_SKIP_AD = "android.support.v4.media.session.action.SKIP_AD";
+ field public static final String ACTION_UNFOLLOW = "android.support.v4.media.session.action.UNFOLLOW";
+ field public static final String ARGUMENT_MEDIA_ATTRIBUTE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE";
+ field public static final String ARGUMENT_MEDIA_ATTRIBUTE_VALUE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE_VALUE";
+ field @Deprecated public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
+ field @Deprecated public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+ field public static final int MEDIA_ATTRIBUTE_ALBUM = 1; // 0x1
+ field public static final int MEDIA_ATTRIBUTE_ARTIST = 0; // 0x0
+ field public static final int MEDIA_ATTRIBUTE_PLAYLIST = 2; // 0x2
+ }
+
+ public abstract static class MediaSessionCompat.Callback {
+ ctor public MediaSessionCompat.Callback();
+ method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+ method public void onCommand(String!, android.os.Bundle!, android.os.ResultReceiver!);
+ method public void onCustomAction(String!, android.os.Bundle!);
+ method public void onFastForward();
+ method public boolean onMediaButtonEvent(android.content.Intent!);
+ method public void onPause();
+ method public void onPlay();
+ method public void onPlayFromMediaId(String!, android.os.Bundle!);
+ method public void onPlayFromSearch(String!, android.os.Bundle!);
+ method public void onPlayFromUri(android.net.Uri!, android.os.Bundle!);
+ method public void onPrepare();
+ method public void onPrepareFromMediaId(String!, android.os.Bundle!);
+ method public void onPrepareFromSearch(String!, android.os.Bundle!);
+ method public void onPrepareFromUri(android.net.Uri!, android.os.Bundle!);
+ method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method @Deprecated public void onRemoveQueueItemAt(int);
+ method public void onRewind();
+ method public void onSeekTo(long);
+ method public void onSetCaptioningEnabled(boolean);
+ method public void onSetPlaybackSpeed(float);
+ method public void onSetRating(android.support.v4.media.RatingCompat!);
+ method public void onSetRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+ method public void onSetRepeatMode(int);
+ method public void onSetShuffleMode(int);
+ method public void onSkipToNext();
+ method public void onSkipToPrevious();
+ method public void onSkipToQueueItem(long);
+ method public void onStop();
+ }
+
+ public static interface MediaSessionCompat.OnActiveChangeListener {
+ method public void onActiveChanged();
+ }
+
+ public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+ ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat!, long);
+ method public int describeContents();
+ method public static android.support.v4.media.session.MediaSessionCompat.QueueItem! fromQueueItem(Object!);
+ method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! fromQueueItemList(java.util.List<?>!);
+ method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+ method public long getQueueId();
+ method public Object! getQueueItem();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! CREATOR;
+ field public static final int UNKNOWN_ID = -1; // 0xffffffff
+ }
+
+ public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.MediaSessionCompat.Token! fromToken(Object!);
+ method public Object! getToken();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token!>! CREATOR;
+ }
+
+ public class ParcelableVolumeInfo implements android.os.Parcelable {
+ ctor public ParcelableVolumeInfo(android.os.Parcel!);
+ ctor public ParcelableVolumeInfo(int, int, int, int, int);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo!>! CREATOR;
+ field public int audioStream;
+ field public int controlType;
+ field public int currentVolume;
+ field public int maxVolume;
+ field public int volumeType;
+ }
+
+ public final class PlaybackStateCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.PlaybackStateCompat! fromPlaybackState(Object!);
+ method public long getActions();
+ method public long getActiveQueueItemId();
+ method public long getBufferedPosition();
+ method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! getCustomActions();
+ method public int getErrorCode();
+ method public CharSequence! getErrorMessage();
+ method public android.os.Bundle? getExtras();
+ method public long getLastPositionUpdateTime();
+ method public float getPlaybackSpeed();
+ method public Object! getPlaybackState();
+ method public long getPosition();
+ method public int getState();
+ method public static int toKeyCode(long);
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+ field public static final long ACTION_PAUSE = 2L; // 0x2L
+ field public static final long ACTION_PLAY = 4L; // 0x4L
+ field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+ field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+ field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+ field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
+ field public static final long ACTION_REWIND = 8L; // 0x8L
+ field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+ field public static final long ACTION_SET_CAPTIONING_ENABLED = 1048576L; // 0x100000L
+ field public static final long ACTION_SET_PLAYBACK_SPEED = 4194304L; // 0x400000L
+ field public static final long ACTION_SET_RATING = 128L; // 0x80L
+ field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+ field public static final long ACTION_SET_SHUFFLE_MODE = 2097152L; // 0x200000L
+ field @Deprecated public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
+ field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+ field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+ field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+ field public static final long ACTION_STOP = 1L; // 0x1L
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat!>! CREATOR;
+ field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+ field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+ field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+ field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+ field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+ field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+ field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+ field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+ field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+ field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+ field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+ field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+ field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+ field public static final int REPEAT_MODE_ALL = 2; // 0x2
+ field public static final int REPEAT_MODE_GROUP = 3; // 0x3
+ field public static final int REPEAT_MODE_INVALID = -1; // 0xffffffff
+ field public static final int REPEAT_MODE_NONE = 0; // 0x0
+ field public static final int REPEAT_MODE_ONE = 1; // 0x1
+ field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
+ field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
+ field public static final int SHUFFLE_MODE_INVALID = -1; // 0xffffffff
+ field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
+ field public static final int STATE_BUFFERING = 6; // 0x6
+ field public static final int STATE_CONNECTING = 8; // 0x8
+ field public static final int STATE_ERROR = 7; // 0x7
+ field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+ field public static final int STATE_NONE = 0; // 0x0
+ field public static final int STATE_PAUSED = 2; // 0x2
+ field public static final int STATE_PLAYING = 3; // 0x3
+ field public static final int STATE_REWINDING = 5; // 0x5
+ field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+ field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+ field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+ field public static final int STATE_STOPPED = 1; // 0x1
+ }
+
+ public static final class PlaybackStateCompat.Builder {
+ ctor public PlaybackStateCompat.Builder();
+ ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(String!, String!, int);
+ method public android.support.v4.media.session.PlaybackStateCompat! build();
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActions(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActiveQueueItemId(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setBufferedPosition(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(int, CharSequence!);
+ method @Deprecated public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(CharSequence!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setExtras(android.os.Bundle!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(int, long, float);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(int, long, float, long);
+ }
+
+ public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction! fromCustomAction(Object!);
+ method public String! getAction();
+ method public Object! getCustomAction();
+ method public android.os.Bundle! getExtras();
+ method public int getIcon();
+ method public CharSequence! getName();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! CREATOR;
+ }
+
+ public static final class PlaybackStateCompat.CustomAction.Builder {
+ ctor public PlaybackStateCompat.CustomAction.Builder(String!, CharSequence!, int);
+ method public android.support.v4.media.session.PlaybackStateCompat.CustomAction! build();
+ method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder! setExtras(android.os.Bundle!);
+ }
+
+}
+
+package androidx.media {
+
+ public class AudioAttributesCompat implements androidx.versionedparcelable.VersionedParcelable {
+ method public int getContentType();
+ method public int getFlags();
+ method public int getLegacyStreamType();
+ method public int getUsage();
+ method public int getVolumeControlStream();
+ method public Object? unwrap();
+ method public static androidx.media.AudioAttributesCompat? wrap(Object);
+ field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
+ field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
+ field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
+ field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
+ field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
+ field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+ field public static final int USAGE_ALARM = 4; // 0x4
+ field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
+ field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
+ field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
+ field public static final int USAGE_ASSISTANT = 16; // 0x10
+ field public static final int USAGE_GAME = 14; // 0xe
+ field public static final int USAGE_MEDIA = 1; // 0x1
+ field public static final int USAGE_NOTIFICATION = 5; // 0x5
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+ field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
+ field public static final int USAGE_NOTIFICATION_RINGTONE = 6; // 0x6
+ field public static final int USAGE_UNKNOWN = 0; // 0x0
+ field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
+ field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
+ }
+
+ public static class AudioAttributesCompat.Builder {
+ ctor public AudioAttributesCompat.Builder();
+ ctor public AudioAttributesCompat.Builder(androidx.media.AudioAttributesCompat!);
+ method public androidx.media.AudioAttributesCompat! build();
+ method public androidx.media.AudioAttributesCompat.Builder! setContentType(int);
+ method public androidx.media.AudioAttributesCompat.Builder! setFlags(int);
+ method public androidx.media.AudioAttributesCompat.Builder! setLegacyStreamType(int);
+ method public androidx.media.AudioAttributesCompat.Builder! setUsage(int);
+ }
+
+ public class AudioFocusRequestCompat {
+ method public androidx.media.AudioAttributesCompat getAudioAttributesCompat();
+ method public android.os.Handler getFocusChangeHandler();
+ method public int getFocusGain();
+ method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+ method public boolean willPauseWhenDucked();
+ }
+
+ public static final class AudioFocusRequestCompat.Builder {
+ ctor public AudioFocusRequestCompat.Builder(androidx.media.AudioFocusRequestCompat);
+ ctor public AudioFocusRequestCompat.Builder(int);
+ method public androidx.media.AudioFocusRequestCompat! build();
+ method public androidx.media.AudioFocusRequestCompat.Builder setAudioAttributes(androidx.media.AudioAttributesCompat);
+ method public androidx.media.AudioFocusRequestCompat.Builder setFocusGain(int);
+ method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
+ method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+ method public androidx.media.AudioFocusRequestCompat.Builder setWillPauseWhenDucked(boolean);
+ }
+
+ public final class AudioManagerCompat {
+ method public static int abandonAudioFocusRequest(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+ method @IntRange(from=0) public static int getStreamMaxVolume(android.media.AudioManager, int);
+ method @IntRange(from=0) public static int getStreamMinVolume(android.media.AudioManager, int);
+ method public static boolean isVolumeFixed(android.media.AudioManager);
+ method public static int requestAudioFocus(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+ field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
+ field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
+ field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
+ field public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; // 0x3
+ }
+
+ public abstract class MediaBrowserServiceCompat extends android.app.Service {
+ ctor public MediaBrowserServiceCompat();
+ method public void dump(java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method public final android.os.Bundle! getBrowserRootHints();
+ method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentBrowserInfo();
+ method public android.support.v4.media.session.MediaSessionCompat.Token? getSessionToken();
+ method public void notifyChildrenChanged(String);
+ method public void notifyChildrenChanged(String, android.os.Bundle);
+ method public android.os.IBinder! onBind(android.content.Intent!);
+ method public void onCustomAction(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<android.os.Bundle!>);
+ method public abstract androidx.media.MediaBrowserServiceCompat.BrowserRoot? onGetRoot(String, int, android.os.Bundle?);
+ method public abstract void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+ method public void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>, android.os.Bundle);
+ method public void onLoadItem(String!, androidx.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+ method public void onSearch(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+ method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token!);
+ field public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+ }
+
+ public static final class MediaBrowserServiceCompat.BrowserRoot {
+ ctor public MediaBrowserServiceCompat.BrowserRoot(String, android.os.Bundle?);
+ method public android.os.Bundle! getExtras();
+ method public String! getRootId();
+ field public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+ field public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+ field public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+ field @Deprecated public static final String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
+ }
+
+ public static class MediaBrowserServiceCompat.Result<T> {
+ method public void detach();
+ method public void sendError(android.os.Bundle?);
+ method public void sendProgressUpdate(android.os.Bundle?);
+ method public void sendResult(T?);
+ }
+
+ public final class MediaSessionManager {
+ method public static androidx.media.MediaSessionManager getSessionManager(android.content.Context);
+ method public boolean isTrustedForMediaControl(androidx.media.MediaSessionManager.RemoteUserInfo);
+ }
+
+ public static final class MediaSessionManager.RemoteUserInfo {
+ ctor public MediaSessionManager.RemoteUserInfo(String, int, int);
+ method public String getPackageName();
+ method public int getPid();
+ method public int getUid();
+ field public static final String LEGACY_CONTROLLER = "android.media.session.MediaController";
+ }
+
+ public abstract class VolumeProviderCompat {
+ ctor public VolumeProviderCompat(int, int, int);
+ method public final int getCurrentVolume();
+ method public final int getMaxVolume();
+ method public final int getVolumeControl();
+ method public Object! getVolumeProvider();
+ method public void onAdjustVolume(int);
+ method public void onSetVolumeTo(int);
+ method public void setCallback(androidx.media.VolumeProviderCompat.Callback!);
+ method public final void setCurrentVolume(int);
+ field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+ field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+ field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+ }
+
+ public abstract static class VolumeProviderCompat.Callback {
+ ctor public VolumeProviderCompat.Callback();
+ method public abstract void onVolumeChanged(androidx.media.VolumeProviderCompat!);
+ }
+
+}
+
+package androidx.media.app {
+
+ public class NotificationCompat {
+ }
+
+ public static class NotificationCompat.DecoratedMediaCustomViewStyle extends androidx.media.app.NotificationCompat.MediaStyle {
+ ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+ }
+
+ public static class NotificationCompat.MediaStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.MediaStyle();
+ ctor public NotificationCompat.MediaStyle(androidx.core.app.NotificationCompat.Builder!);
+ method public static android.support.v4.media.session.MediaSessionCompat.Token! getMediaSession(android.app.Notification!);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setCancelButtonIntent(android.app.PendingIntent!);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token!);
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public androidx.media.app.NotificationCompat.MediaStyle setRemotePlaybackInfo(CharSequence, @DrawableRes int, android.app.PendingIntent?);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setShowActionsInCompactView(int...);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setShowCancelButton(boolean);
+ }
+
+}
+
+package androidx.media.session {
+
+ public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+ ctor public MediaButtonReceiver();
+ method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, android.content.ComponentName!, long);
+ method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, long);
+ method public static android.view.KeyEvent! handleIntent(android.support.v4.media.session.MediaSessionCompat!, android.content.Intent!);
+ method @RequiresApi(31) protected void onForegroundServiceStartNotAllowedException(android.content.Intent, android.app.ForegroundServiceStartNotAllowedException);
+ method public void onReceive(android.content.Context!, android.content.Intent!);
+ }
+
+}
+
+package androidx.media.utils {
+
+ public final class MediaConstants {
+ field public static final String BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT = "androidx.media.utils.MediaBrowserCompat.extras.CUSTOM_BROWSER_ACTION_LIMIT";
+ field public static final String BROWSER_ROOT_HINTS_KEY_MEDIA_ART_SIZE_PIXELS = "android.media.extras.MEDIA_ART_SIZE_HINT_PIXELS";
+ field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_LIMIT";
+ field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_SUPPORTED_FLAGS";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.BrowserRoot.Extras.APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST = "androidx.media.utils.extras.CUSTOM_BROWSER_ACTION_ROOT_LIST";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_FAVORITES_MEDIA_ITEM = "androidx.media.BrowserRoot.Extras.FAVORITES_MEDIA_ITEM";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED = "android.media.browse.SEARCH_SUPPORTED";
+ field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE = "androidx.media.MediaItem.Extras.COMPLETION_PERCENTAGE";
+ field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS = "android.media.extra.PLAYBACK_STATUS";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE = "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE = "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE = "android.media.browse.CONTENT_STYLE_PLAYABLE_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM = "android.media.browse.CONTENT_STYLE_SINGLE_ITEM_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST = "androidx.media.utils.extras.CUSTOM_BROWSER_ACTION_ID_LIST";
+ field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED = 2; // 0x2
+ field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED = 0; // 0x0
+ field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED = 1; // 0x1
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM = 4; // 0x4
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM = 3; // 0x3
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM = 2; // 0x2
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM = 1; // 0x1
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_EXTRAS = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_EXTRAS";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_ICON_URI";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_ID";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_LABEL";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM";
+ field public static final String METADATA_KEY_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_CONTENT_ID";
+ field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+ field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
+ field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+ field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
+ field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.PlaybackStateCompat.Extras.ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT";
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID = "androidx.media.PlaybackStateCompat.Extras.KEY_MEDIA_ID";
+ field public static final String SESSION_EXTRAS_KEY_ACCOUNT_NAME = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_NAME";
+ field public static final String SESSION_EXTRAS_KEY_ACCOUNT_TYPE = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_TYPE";
+ field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
+ field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
+ field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+ field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_SHUFFLE = "androidx.media.MediaControllerCompat.TransportControls.extras.KEY_SHUFFLE";
+ }
+
+}
+
diff --git a/media/media/api/res-1.7.0-beta01.txt b/media/media/api/res-1.7.0-beta01.txt
new file mode 100644
index 0000000..7a1e44d
--- /dev/null
+++ b/media/media/api/res-1.7.0-beta01.txt
@@ -0,0 +1,5 @@
+style TextAppearance_Compat_Notification_Info_Media
+style TextAppearance_Compat_Notification_Line2_Media
+style TextAppearance_Compat_Notification_Media
+style TextAppearance_Compat_Notification_Time_Media
+style TextAppearance_Compat_Notification_Title_Media
diff --git a/media/media/api/restricted_1.7.0-beta01.txt b/media/media/api/restricted_1.7.0-beta01.txt
new file mode 100644
index 0000000..4f0864c
--- /dev/null
+++ b/media/media/api/restricted_1.7.0-beta01.txt
@@ -0,0 +1,804 @@
+// Signature format: 4.0
+package android.support.v4.media {
+
+ public final class MediaBrowserCompat {
+ ctor public MediaBrowserCompat(android.content.Context!, android.content.ComponentName!, android.support.v4.media.MediaBrowserCompat.ConnectionCallback!, android.os.Bundle!);
+ method public void connect();
+ method public void disconnect();
+ method public android.os.Bundle? getExtras();
+ method public void getItem(String, android.support.v4.media.MediaBrowserCompat.ItemCallback);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.Bundle? getNotifyChildrenChangedOptions();
+ method public String getRoot();
+ method public android.content.ComponentName getServiceComponent();
+ method public android.support.v4.media.session.MediaSessionCompat.Token getSessionToken();
+ method public boolean isConnected();
+ method public void search(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.SearchCallback);
+ method public void sendCustomAction(String, android.os.Bundle!, android.support.v4.media.MediaBrowserCompat.CustomActionCallback?);
+ method public void subscribe(String, android.os.Bundle, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+ method public void subscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+ method public void unsubscribe(String);
+ method public void unsubscribe(String, android.support.v4.media.MediaBrowserCompat.SubscriptionCallback);
+ field public static final String CUSTOM_ACTION_DOWNLOAD = "android.support.v4.media.action.DOWNLOAD";
+ field public static final String CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE = "android.support.v4.media.action.REMOVE_DOWNLOADED_FILE";
+ field public static final String EXTRA_DOWNLOAD_PROGRESS = "android.media.browse.extra.DOWNLOAD_PROGRESS";
+ field public static final String EXTRA_MEDIA_ID = "android.media.browse.extra.MEDIA_ID";
+ field public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
+ field public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
+ }
+
+ public static class MediaBrowserCompat.ConnectionCallback {
+ ctor public MediaBrowserCompat.ConnectionCallback();
+ method public void onConnected();
+ method public void onConnectionFailed();
+ method public void onConnectionSuspended();
+ }
+
+ public abstract static class MediaBrowserCompat.CustomActionCallback {
+ ctor public MediaBrowserCompat.CustomActionCallback();
+ method public void onError(String!, android.os.Bundle!, android.os.Bundle!);
+ method public void onProgressUpdate(String!, android.os.Bundle!, android.os.Bundle!);
+ method public void onResult(String!, android.os.Bundle!, android.os.Bundle!);
+ }
+
+ public abstract static class MediaBrowserCompat.ItemCallback {
+ ctor public MediaBrowserCompat.ItemCallback();
+ method public void onError(String);
+ method public void onItemLoaded(android.support.v4.media.MediaBrowserCompat.MediaItem!);
+ }
+
+ public static class MediaBrowserCompat.MediaItem implements android.os.Parcelable {
+ ctor public MediaBrowserCompat.MediaItem(android.support.v4.media.MediaDescriptionCompat, int);
+ method public int describeContents();
+ method public static android.support.v4.media.MediaBrowserCompat.MediaItem! fromMediaItem(Object!);
+ method public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>! fromMediaItemList(java.util.List<?>!);
+ method public android.support.v4.media.MediaDescriptionCompat getDescription();
+ method public int getFlags();
+ method public String? getMediaId();
+ method public boolean isBrowsable();
+ method public boolean isPlayable();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaBrowserCompat.MediaItem!>! CREATOR;
+ field public static final int FLAG_BROWSABLE = 1; // 0x1
+ field public static final int FLAG_PLAYABLE = 2; // 0x2
+ }
+
+ public abstract static class MediaBrowserCompat.SearchCallback {
+ ctor public MediaBrowserCompat.SearchCallback();
+ method public void onError(String, android.os.Bundle!);
+ method public void onSearchResult(String, android.os.Bundle!, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+ }
+
+ public abstract static class MediaBrowserCompat.SubscriptionCallback {
+ ctor public MediaBrowserCompat.SubscriptionCallback();
+ method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+ method public void onChildrenLoaded(String, java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>, android.os.Bundle);
+ method public void onError(String);
+ method public void onError(String, android.os.Bundle);
+ }
+
+ public final class MediaDescriptionCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.MediaDescriptionCompat! fromMediaDescription(Object!);
+ method public CharSequence? getDescription();
+ method public android.os.Bundle? getExtras();
+ method public android.graphics.Bitmap? getIconBitmap();
+ method public android.net.Uri? getIconUri();
+ method public Object! getMediaDescription();
+ method public String? getMediaId();
+ method public android.net.Uri? getMediaUri();
+ method public CharSequence? getSubtitle();
+ method public CharSequence? getTitle();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final long BT_FOLDER_TYPE_ALBUMS = 2L; // 0x2L
+ field public static final long BT_FOLDER_TYPE_ARTISTS = 3L; // 0x3L
+ field public static final long BT_FOLDER_TYPE_GENRES = 4L; // 0x4L
+ field public static final long BT_FOLDER_TYPE_MIXED = 0L; // 0x0L
+ field public static final long BT_FOLDER_TYPE_PLAYLISTS = 5L; // 0x5L
+ field public static final long BT_FOLDER_TYPE_TITLES = 1L; // 0x1L
+ field public static final long BT_FOLDER_TYPE_YEARS = 6L; // 0x6L
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaDescriptionCompat!>! CREATOR;
+ field public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
+ field public static final String EXTRA_DOWNLOAD_STATUS = "android.media.extra.DOWNLOAD_STATUS";
+ field public static final long STATUS_DOWNLOADED = 2L; // 0x2L
+ field public static final long STATUS_DOWNLOADING = 1L; // 0x1L
+ field public static final long STATUS_NOT_DOWNLOADED = 0L; // 0x0L
+ }
+
+ public static final class MediaDescriptionCompat.Builder {
+ ctor public MediaDescriptionCompat.Builder();
+ method public android.support.v4.media.MediaDescriptionCompat! build();
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setDescription(CharSequence?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setExtras(android.os.Bundle?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconBitmap(android.graphics.Bitmap?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setIconUri(android.net.Uri?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaId(String?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setMediaUri(android.net.Uri?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setSubtitle(CharSequence?);
+ method public android.support.v4.media.MediaDescriptionCompat.Builder! setTitle(CharSequence?);
+ }
+
+ public final class MediaMetadataCompat implements android.os.Parcelable {
+ method public boolean containsKey(String!);
+ method public int describeContents();
+ method public static android.support.v4.media.MediaMetadataCompat! fromMediaMetadata(Object!);
+ method public android.graphics.Bitmap! getBitmap(String!);
+ method public android.os.Bundle! getBundle();
+ method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+ method public long getLong(String!);
+ method public Object! getMediaMetadata();
+ method public android.support.v4.media.RatingCompat! getRating(String!);
+ method public String! getString(String!);
+ method public CharSequence! getText(String!);
+ method public java.util.Set<java.lang.String!>! keySet();
+ method public int size();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.MediaMetadataCompat!>! CREATOR;
+ field public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+ field public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
+ field public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
+ field public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
+ field public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
+ field public static final String METADATA_KEY_ART = "android.media.metadata.ART";
+ field public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
+ field public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
+ field public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
+ field public static final String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE";
+ field public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
+ field public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
+ field public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
+ field public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
+ field public static final String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION";
+ field public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
+ field public static final String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI";
+ field public static final String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE";
+ field public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
+ field public static final String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS";
+ field public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
+ field public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+ field public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+ field public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
+ field public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
+ field public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
+ field public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
+ field public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
+ field public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
+ field public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
+ field public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
+ }
+
+ public static final class MediaMetadataCompat.Builder {
+ ctor public MediaMetadataCompat.Builder();
+ ctor public MediaMetadataCompat.Builder(android.support.v4.media.MediaMetadataCompat!);
+ method public android.support.v4.media.MediaMetadataCompat! build();
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putBitmap(String!, android.graphics.Bitmap!);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putLong(String!, long);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putRating(String!, android.support.v4.media.RatingCompat!);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putString(String!, String!);
+ method public android.support.v4.media.MediaMetadataCompat.Builder! putText(String!, CharSequence!);
+ }
+
+ public final class RatingCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.RatingCompat! fromRating(Object!);
+ method public float getPercentRating();
+ method public Object! getRating();
+ method @android.support.v4.media.RatingCompat.Style public int getRatingStyle();
+ method public float getStarRating();
+ method public boolean hasHeart();
+ method public boolean isRated();
+ method public boolean isThumbUp();
+ method public static android.support.v4.media.RatingCompat! newHeartRating(boolean);
+ method public static android.support.v4.media.RatingCompat! newPercentageRating(float);
+ method public static android.support.v4.media.RatingCompat! newStarRating(int, float);
+ method public static android.support.v4.media.RatingCompat! newThumbRating(boolean);
+ method public static android.support.v4.media.RatingCompat! newUnratedRating(@android.support.v4.media.RatingCompat.Style int);
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.RatingCompat!>! CREATOR;
+ field public static final int RATING_3_STARS = 3; // 0x3
+ field public static final int RATING_4_STARS = 4; // 0x4
+ field public static final int RATING_5_STARS = 5; // 0x5
+ field public static final int RATING_HEART = 1; // 0x1
+ field public static final int RATING_NONE = 0; // 0x0
+ field public static final int RATING_PERCENTAGE = 6; // 0x6
+ field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2
+ }
+
+ @IntDef({android.support.v4.media.RatingCompat.RATING_NONE, android.support.v4.media.RatingCompat.RATING_HEART, android.support.v4.media.RatingCompat.RATING_THUMB_UP_DOWN, android.support.v4.media.RatingCompat.RATING_3_STARS, android.support.v4.media.RatingCompat.RATING_4_STARS, android.support.v4.media.RatingCompat.RATING_5_STARS, android.support.v4.media.RatingCompat.RATING_PERCENTAGE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RatingCompat.Style {
+ }
+
+}
+
+package android.support.v4.media.session {
+
+ public final class MediaControllerCompat {
+ ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat);
+ ctor public MediaControllerCompat(android.content.Context!, android.support.v4.media.session.MediaSessionCompat.Token);
+ method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method public void addQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+ method public void adjustVolume(int, int);
+ method public boolean dispatchMediaButtonEvent(android.view.KeyEvent!);
+ method public android.os.Bundle! getExtras();
+ method public long getFlags();
+ method public Object! getMediaController();
+ method public static android.support.v4.media.session.MediaControllerCompat! getMediaController(android.app.Activity);
+ method public android.support.v4.media.MediaMetadataCompat! getMetadata();
+ method public String! getPackageName();
+ method public android.support.v4.media.session.MediaControllerCompat.PlaybackInfo! getPlaybackInfo();
+ method public android.support.v4.media.session.PlaybackStateCompat! getPlaybackState();
+ method public java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! getQueue();
+ method public CharSequence! getQueueTitle();
+ method public int getRatingType();
+ method public int getRepeatMode();
+ method public android.app.PendingIntent! getSessionActivity();
+ method public android.os.Bundle getSessionInfo();
+ method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+ method public int getShuffleMode();
+ method public android.support.v4.media.session.MediaControllerCompat.TransportControls! getTransportControls();
+ method public boolean isCaptioningEnabled();
+ method public boolean isSessionReady();
+ method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+ method public void registerCallback(android.support.v4.media.session.MediaControllerCompat.Callback, android.os.Handler!);
+ method public void removeQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method @Deprecated public void removeQueueItemAt(int);
+ method public void sendCommand(String, android.os.Bundle?, android.os.ResultReceiver?);
+ method public static void setMediaController(android.app.Activity, android.support.v4.media.session.MediaControllerCompat!);
+ method public void setVolumeTo(int, int);
+ method public void unregisterCallback(android.support.v4.media.session.MediaControllerCompat.Callback);
+ }
+
+ public abstract static class MediaControllerCompat.Callback implements android.os.IBinder.DeathRecipient {
+ ctor public MediaControllerCompat.Callback();
+ method public void binderDied();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.support.v4.media.session.IMediaControllerCallback! getIControllerCallback();
+ method public void onAudioInfoChanged(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo!);
+ method public void onCaptioningEnabledChanged(boolean);
+ method public void onExtrasChanged(android.os.Bundle!);
+ method public void onMetadataChanged(android.support.v4.media.MediaMetadataCompat!);
+ method public void onPlaybackStateChanged(android.support.v4.media.session.PlaybackStateCompat!);
+ method public void onQueueChanged(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+ method public void onQueueTitleChanged(CharSequence!);
+ method public void onRepeatModeChanged(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+ method public void onSessionDestroyed();
+ method public void onSessionEvent(String!, android.os.Bundle!);
+ method public void onSessionReady();
+ method public void onShuffleModeChanged(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+ }
+
+ public static final class MediaControllerCompat.PlaybackInfo {
+ method public androidx.media.AudioAttributesCompat getAudioAttributes();
+ method @Deprecated public int getAudioStream();
+ method public int getCurrentVolume();
+ method public int getMaxVolume();
+ method public int getPlaybackType();
+ method public int getVolumeControl();
+ field public static final int PLAYBACK_TYPE_LOCAL = 1; // 0x1
+ field public static final int PLAYBACK_TYPE_REMOTE = 2; // 0x2
+ }
+
+ public abstract static class MediaControllerCompat.TransportControls {
+ method public abstract void fastForward();
+ method public abstract void pause();
+ method public abstract void play();
+ method public abstract void playFromMediaId(String!, android.os.Bundle!);
+ method public abstract void playFromSearch(String!, android.os.Bundle!);
+ method public abstract void playFromUri(android.net.Uri!, android.os.Bundle!);
+ method public abstract void prepare();
+ method public abstract void prepareFromMediaId(String!, android.os.Bundle!);
+ method public abstract void prepareFromSearch(String!, android.os.Bundle!);
+ method public abstract void prepareFromUri(android.net.Uri!, android.os.Bundle!);
+ method public abstract void rewind();
+ method public abstract void seekTo(long);
+ method public abstract void sendCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!, android.os.Bundle!);
+ method public abstract void sendCustomAction(String!, android.os.Bundle!);
+ method public abstract void setCaptioningEnabled(boolean);
+ method public void setPlaybackSpeed(float);
+ method public abstract void setRating(android.support.v4.media.RatingCompat!);
+ method public abstract void setRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+ method public abstract void setRepeatMode(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+ method public abstract void setShuffleMode(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+ method public abstract void skipToNext();
+ method public abstract void skipToPrevious();
+ method public abstract void skipToQueueItem(long);
+ method public abstract void stop();
+ field @Deprecated public static final String EXTRA_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+ }
+
+ public class MediaSessionCompat {
+ ctor public MediaSessionCompat(android.content.Context, String);
+ ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?);
+ ctor public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?, android.os.Bundle?);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public MediaSessionCompat(android.content.Context, String, android.content.ComponentName?, android.app.PendingIntent?, android.os.Bundle?, androidx.versionedparcelable.VersionedParcelable?);
+ method public void addOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+ method public static android.support.v4.media.session.MediaSessionCompat! fromMediaSession(android.content.Context!, Object!);
+ method public android.support.v4.media.session.MediaControllerCompat! getController();
+ method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
+ method public Object! getMediaSession();
+ method public Object! getRemoteControlClient();
+ method public android.support.v4.media.session.MediaSessionCompat.Token! getSessionToken();
+ method public boolean isActive();
+ method public void release();
+ method public void removeOnActiveChangeListener(android.support.v4.media.session.MediaSessionCompat.OnActiveChangeListener!);
+ method public void sendSessionEvent(String!, android.os.Bundle!);
+ method public void setActive(boolean);
+ method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!);
+ method public void setCallback(android.support.v4.media.session.MediaSessionCompat.Callback!, android.os.Handler!);
+ method public void setCaptioningEnabled(boolean);
+ method public void setExtras(android.os.Bundle!);
+ method public void setFlags(int);
+ method public void setMediaButtonReceiver(android.app.PendingIntent!);
+ method public void setMetadata(android.support.v4.media.MediaMetadataCompat!);
+ method public void setPlaybackState(android.support.v4.media.session.PlaybackStateCompat!);
+ method public void setPlaybackToLocal(int);
+ method public void setPlaybackToRemote(androidx.media.VolumeProviderCompat!);
+ method public void setQueue(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>!);
+ method public void setQueueTitle(CharSequence!);
+ method public void setRatingType(@android.support.v4.media.RatingCompat.Style int);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setRegistrationCallback(android.support.v4.media.session.MediaSessionCompat.RegistrationCallback?, android.os.Handler);
+ method public void setRepeatMode(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+ method public void setSessionActivity(android.app.PendingIntent!);
+ method public void setShuffleMode(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+ field public static final String ACTION_FLAG_AS_INAPPROPRIATE = "android.support.v4.media.session.action.FLAG_AS_INAPPROPRIATE";
+ field public static final String ACTION_FOLLOW = "android.support.v4.media.session.action.FOLLOW";
+ field public static final String ACTION_SKIP_AD = "android.support.v4.media.session.action.SKIP_AD";
+ field public static final String ACTION_UNFOLLOW = "android.support.v4.media.session.action.UNFOLLOW";
+ field public static final String ARGUMENT_MEDIA_ATTRIBUTE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE";
+ field public static final String ARGUMENT_MEDIA_ATTRIBUTE_VALUE = "android.support.v4.media.session.ARGUMENT_MEDIA_ATTRIBUTE_VALUE";
+ field @Deprecated public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+ field public static final int FLAG_HANDLES_QUEUE_COMMANDS = 4; // 0x4
+ field @Deprecated public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
+ field public static final int MEDIA_ATTRIBUTE_ALBUM = 1; // 0x1
+ field public static final int MEDIA_ATTRIBUTE_ARTIST = 0; // 0x0
+ field public static final int MEDIA_ATTRIBUTE_PLAYLIST = 2; // 0x2
+ }
+
+ public abstract static class MediaSessionCompat.Callback {
+ ctor public MediaSessionCompat.Callback();
+ method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method public void onAddQueueItem(android.support.v4.media.MediaDescriptionCompat!, int);
+ method public void onCommand(String!, android.os.Bundle!, android.os.ResultReceiver!);
+ method public void onCustomAction(String!, android.os.Bundle!);
+ method public void onFastForward();
+ method public boolean onMediaButtonEvent(android.content.Intent!);
+ method public void onPause();
+ method public void onPlay();
+ method public void onPlayFromMediaId(String!, android.os.Bundle!);
+ method public void onPlayFromSearch(String!, android.os.Bundle!);
+ method public void onPlayFromUri(android.net.Uri!, android.os.Bundle!);
+ method public void onPrepare();
+ method public void onPrepareFromMediaId(String!, android.os.Bundle!);
+ method public void onPrepareFromSearch(String!, android.os.Bundle!);
+ method public void onPrepareFromUri(android.net.Uri!, android.os.Bundle!);
+ method public void onRemoveQueueItem(android.support.v4.media.MediaDescriptionCompat!);
+ method @Deprecated public void onRemoveQueueItemAt(int);
+ method public void onRewind();
+ method public void onSeekTo(long);
+ method public void onSetCaptioningEnabled(boolean);
+ method public void onSetPlaybackSpeed(float);
+ method public void onSetRating(android.support.v4.media.RatingCompat!);
+ method public void onSetRating(android.support.v4.media.RatingCompat!, android.os.Bundle!);
+ method public void onSetRepeatMode(@android.support.v4.media.session.PlaybackStateCompat.RepeatMode int);
+ method public void onSetShuffleMode(@android.support.v4.media.session.PlaybackStateCompat.ShuffleMode int);
+ method public void onSkipToNext();
+ method public void onSkipToPrevious();
+ method public void onSkipToQueueItem(long);
+ method public void onStop();
+ }
+
+ public static interface MediaSessionCompat.OnActiveChangeListener {
+ method public void onActiveChanged();
+ }
+
+ public static final class MediaSessionCompat.QueueItem implements android.os.Parcelable {
+ ctor public MediaSessionCompat.QueueItem(android.support.v4.media.MediaDescriptionCompat!, long);
+ method public int describeContents();
+ method public static android.support.v4.media.session.MediaSessionCompat.QueueItem! fromQueueItem(Object!);
+ method public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! fromQueueItemList(java.util.List<?>!);
+ method public android.support.v4.media.MediaDescriptionCompat! getDescription();
+ method public long getQueueId();
+ method public Object! getQueueItem();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.QueueItem!>! CREATOR;
+ field public static final int UNKNOWN_ID = -1; // 0xffffffff
+ }
+
+ @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface MediaSessionCompat.RegistrationCallback {
+ method public void onCallbackRegistered(int, int);
+ method public void onCallbackUnregistered(int, int);
+ }
+
+ public static final class MediaSessionCompat.Token implements android.os.Parcelable {
+ method public int describeContents();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.support.v4.media.session.MediaSessionCompat.Token! fromBundle(android.os.Bundle!);
+ method public static android.support.v4.media.session.MediaSessionCompat.Token! fromToken(Object!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.versionedparcelable.VersionedParcelable! getSession2Token();
+ method public Object! getToken();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSession2Token(androidx.versionedparcelable.VersionedParcelable!);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.Bundle! toBundle();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.MediaSessionCompat.Token!>! CREATOR;
+ }
+
+ public class ParcelableVolumeInfo implements android.os.Parcelable {
+ ctor public ParcelableVolumeInfo(android.os.Parcel!);
+ ctor public ParcelableVolumeInfo(int, int, int, int, int);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.ParcelableVolumeInfo!>! CREATOR;
+ field public int audioStream;
+ field public int controlType;
+ field public int currentVolume;
+ field public int maxVolume;
+ field public int volumeType;
+ }
+
+ public final class PlaybackStateCompat implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.PlaybackStateCompat! fromPlaybackState(Object!);
+ method @android.support.v4.media.session.PlaybackStateCompat.Actions public long getActions();
+ method public long getActiveQueueItemId();
+ method public long getBufferedPosition();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public long getCurrentPosition(Long!);
+ method public java.util.List<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! getCustomActions();
+ method public int getErrorCode();
+ method public CharSequence! getErrorMessage();
+ method public android.os.Bundle? getExtras();
+ method public long getLastPositionUpdateTime();
+ method public float getPlaybackSpeed();
+ method public Object! getPlaybackState();
+ method public long getPosition();
+ method @android.support.v4.media.session.PlaybackStateCompat.State public int getState();
+ method public static int toKeyCode(long);
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
+ field public static final long ACTION_PAUSE = 2L; // 0x2L
+ field public static final long ACTION_PLAY = 4L; // 0x4L
+ field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
+ field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
+ field public static final long ACTION_PLAY_FROM_URI = 8192L; // 0x2000L
+ field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
+ field public static final long ACTION_PREPARE = 16384L; // 0x4000L
+ field public static final long ACTION_PREPARE_FROM_MEDIA_ID = 32768L; // 0x8000L
+ field public static final long ACTION_PREPARE_FROM_SEARCH = 65536L; // 0x10000L
+ field public static final long ACTION_PREPARE_FROM_URI = 131072L; // 0x20000L
+ field public static final long ACTION_REWIND = 8L; // 0x8L
+ field public static final long ACTION_SEEK_TO = 256L; // 0x100L
+ field public static final long ACTION_SET_CAPTIONING_ENABLED = 1048576L; // 0x100000L
+ field public static final long ACTION_SET_PLAYBACK_SPEED = 4194304L; // 0x400000L
+ field public static final long ACTION_SET_RATING = 128L; // 0x80L
+ field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L
+ field public static final long ACTION_SET_SHUFFLE_MODE = 2097152L; // 0x200000L
+ field @Deprecated public static final long ACTION_SET_SHUFFLE_MODE_ENABLED = 524288L; // 0x80000L
+ field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
+ field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+ field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
+ field public static final long ACTION_STOP = 1L; // 0x1L
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat!>! CREATOR;
+ field public static final int ERROR_CODE_ACTION_ABORTED = 10; // 0xa
+ field public static final int ERROR_CODE_APP_ERROR = 1; // 0x1
+ field public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3; // 0x3
+ field public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5; // 0x5
+ field public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8; // 0x8
+ field public static final int ERROR_CODE_END_OF_QUEUE = 11; // 0xb
+ field public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7; // 0x7
+ field public static final int ERROR_CODE_NOT_SUPPORTED = 2; // 0x2
+ field public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6; // 0x6
+ field public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4; // 0x4
+ field public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9; // 0x9
+ field public static final int ERROR_CODE_UNKNOWN_ERROR = 0; // 0x0
+ field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
+ field public static final int REPEAT_MODE_ALL = 2; // 0x2
+ field public static final int REPEAT_MODE_GROUP = 3; // 0x3
+ field public static final int REPEAT_MODE_INVALID = -1; // 0xffffffff
+ field public static final int REPEAT_MODE_NONE = 0; // 0x0
+ field public static final int REPEAT_MODE_ONE = 1; // 0x1
+ field public static final int SHUFFLE_MODE_ALL = 1; // 0x1
+ field public static final int SHUFFLE_MODE_GROUP = 2; // 0x2
+ field public static final int SHUFFLE_MODE_INVALID = -1; // 0xffffffff
+ field public static final int SHUFFLE_MODE_NONE = 0; // 0x0
+ field public static final int STATE_BUFFERING = 6; // 0x6
+ field public static final int STATE_CONNECTING = 8; // 0x8
+ field public static final int STATE_ERROR = 7; // 0x7
+ field public static final int STATE_FAST_FORWARDING = 4; // 0x4
+ field public static final int STATE_NONE = 0; // 0x0
+ field public static final int STATE_PAUSED = 2; // 0x2
+ field public static final int STATE_PLAYING = 3; // 0x3
+ field public static final int STATE_REWINDING = 5; // 0x5
+ field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
+ field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+ field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
+ field public static final int STATE_STOPPED = 1; // 0x1
+ }
+
+ @LongDef(flag=true, value={android.support.v4.media.session.PlaybackStateCompat.ACTION_STOP, android.support.v4.media.session.PlaybackStateCompat.ACTION_PAUSE, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY, android.support.v4.media.session.PlaybackStateCompat.ACTION_REWIND, android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS, android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_NEXT, android.support.v4.media.session.PlaybackStateCompat.ACTION_FAST_FORWARD, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_RATING, android.support.v4.media.session.PlaybackStateCompat.ACTION_SEEK_TO, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_PAUSE, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH, android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM, android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_FROM_URI, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE_FROM_MEDIA_ID, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE_FROM_SEARCH, android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE_FROM_URI, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_REPEAT_MODE, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_CAPTIONING_ENABLED, android.support.v4.media.session.PlaybackStateCompat.ACTION_SET_PLAYBACK_SPEED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.Actions {
+ }
+
+ public static final class PlaybackStateCompat.Builder {
+ ctor public PlaybackStateCompat.Builder();
+ ctor public PlaybackStateCompat.Builder(android.support.v4.media.session.PlaybackStateCompat!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(android.support.v4.media.session.PlaybackStateCompat.CustomAction!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! addCustomAction(String!, String!, int);
+ method public android.support.v4.media.session.PlaybackStateCompat! build();
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActions(@android.support.v4.media.session.PlaybackStateCompat.Actions long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setActiveQueueItemId(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setBufferedPosition(long);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(int, CharSequence!);
+ method @Deprecated public android.support.v4.media.session.PlaybackStateCompat.Builder! setErrorMessage(CharSequence!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setExtras(android.os.Bundle!);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(@android.support.v4.media.session.PlaybackStateCompat.State int, long, float);
+ method public android.support.v4.media.session.PlaybackStateCompat.Builder! setState(@android.support.v4.media.session.PlaybackStateCompat.State int, long, float, long);
+ }
+
+ public static final class PlaybackStateCompat.CustomAction implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.support.v4.media.session.PlaybackStateCompat.CustomAction! fromCustomAction(Object!);
+ method public String! getAction();
+ method public Object! getCustomAction();
+ method public android.os.Bundle! getExtras();
+ method public int getIcon();
+ method public CharSequence! getName();
+ method public void writeToParcel(android.os.Parcel!, int);
+ field public static final android.os.Parcelable.Creator<android.support.v4.media.session.PlaybackStateCompat.CustomAction!>! CREATOR;
+ }
+
+ public static final class PlaybackStateCompat.CustomAction.Builder {
+ ctor public PlaybackStateCompat.CustomAction.Builder(String!, CharSequence!, int);
+ method public android.support.v4.media.session.PlaybackStateCompat.CustomAction! build();
+ method public android.support.v4.media.session.PlaybackStateCompat.CustomAction.Builder! setExtras(android.os.Bundle!);
+ }
+
+ @IntDef({android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_INVALID, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_NONE, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_ONE, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_ALL, android.support.v4.media.session.PlaybackStateCompat.REPEAT_MODE_GROUP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.RepeatMode {
+ }
+
+ @IntDef({android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_INVALID, android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_NONE, android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_ALL, android.support.v4.media.session.PlaybackStateCompat.SHUFFLE_MODE_GROUP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.ShuffleMode {
+ }
+
+ @IntDef({android.support.v4.media.session.PlaybackStateCompat.STATE_NONE, android.support.v4.media.session.PlaybackStateCompat.STATE_STOPPED, android.support.v4.media.session.PlaybackStateCompat.STATE_PAUSED, android.support.v4.media.session.PlaybackStateCompat.STATE_PLAYING, android.support.v4.media.session.PlaybackStateCompat.STATE_FAST_FORWARDING, android.support.v4.media.session.PlaybackStateCompat.STATE_REWINDING, android.support.v4.media.session.PlaybackStateCompat.STATE_BUFFERING, android.support.v4.media.session.PlaybackStateCompat.STATE_ERROR, android.support.v4.media.session.PlaybackStateCompat.STATE_CONNECTING, android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS, android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_NEXT, android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PlaybackStateCompat.State {
+ }
+
+}
+
+package androidx.media {
+
+ @androidx.versionedparcelable.VersionedParcelize(jetifyAs="android.support.v4.media.AudioAttributesCompat") public class AudioAttributesCompat implements androidx.versionedparcelable.VersionedParcelable {
+ method public int getContentType();
+ method public int getFlags();
+ method public int getLegacyStreamType();
+ method public int getUsage();
+ method public int getVolumeControlStream();
+ method public Object? unwrap();
+ method public static androidx.media.AudioAttributesCompat? wrap(Object);
+ field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
+ field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
+ field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
+ field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1
+ field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0
+ field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
+ field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
+ field public static final int USAGE_ALARM = 4; // 0x4
+ field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
+ field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
+ field public static final int USAGE_ASSISTANCE_SONIFICATION = 13; // 0xd
+ field public static final int USAGE_ASSISTANT = 16; // 0x10
+ field public static final int USAGE_GAME = 14; // 0xe
+ field public static final int USAGE_MEDIA = 1; // 0x1
+ field public static final int USAGE_NOTIFICATION = 5; // 0x5
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; // 0x9
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; // 0x8
+ field public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; // 0x7
+ field public static final int USAGE_NOTIFICATION_EVENT = 10; // 0xa
+ field public static final int USAGE_NOTIFICATION_RINGTONE = 6; // 0x6
+ field public static final int USAGE_UNKNOWN = 0; // 0x0
+ field public static final int USAGE_VOICE_COMMUNICATION = 2; // 0x2
+ field public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; // 0x3
+ }
+
+ public static class AudioAttributesCompat.Builder {
+ ctor public AudioAttributesCompat.Builder();
+ ctor public AudioAttributesCompat.Builder(androidx.media.AudioAttributesCompat!);
+ method public androidx.media.AudioAttributesCompat! build();
+ method public androidx.media.AudioAttributesCompat.Builder! setContentType(int);
+ method public androidx.media.AudioAttributesCompat.Builder! setFlags(int);
+ method public androidx.media.AudioAttributesCompat.Builder! setLegacyStreamType(int);
+ method public androidx.media.AudioAttributesCompat.Builder! setUsage(int);
+ }
+
+ public class AudioFocusRequestCompat {
+ method public androidx.media.AudioAttributesCompat getAudioAttributesCompat();
+ method public android.os.Handler getFocusChangeHandler();
+ method public int getFocusGain();
+ method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
+ method public boolean willPauseWhenDucked();
+ }
+
+ public static final class AudioFocusRequestCompat.Builder {
+ ctor public AudioFocusRequestCompat.Builder(androidx.media.AudioFocusRequestCompat);
+ ctor public AudioFocusRequestCompat.Builder(int);
+ method public androidx.media.AudioFocusRequestCompat! build();
+ method public androidx.media.AudioFocusRequestCompat.Builder setAudioAttributes(androidx.media.AudioAttributesCompat);
+ method public androidx.media.AudioFocusRequestCompat.Builder setFocusGain(int);
+ method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener);
+ method public androidx.media.AudioFocusRequestCompat.Builder setOnAudioFocusChangeListener(android.media.AudioManager.OnAudioFocusChangeListener, android.os.Handler);
+ method public androidx.media.AudioFocusRequestCompat.Builder setWillPauseWhenDucked(boolean);
+ }
+
+ public final class AudioManagerCompat {
+ method public static int abandonAudioFocusRequest(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+ method @IntRange(from=0) public static int getStreamMaxVolume(android.media.AudioManager, @androidx.core.app.NotificationCompat.StreamType int);
+ method @IntRange(from=0) public static int getStreamMinVolume(android.media.AudioManager, @androidx.core.app.NotificationCompat.StreamType int);
+ method public static boolean isVolumeFixed(android.media.AudioManager);
+ method public static int requestAudioFocus(android.media.AudioManager, androidx.media.AudioFocusRequestCompat);
+ field public static final int AUDIOFOCUS_GAIN = 1; // 0x1
+ field public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; // 0x2
+ field public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; // 0x4
+ field public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; // 0x3
+ }
+
+ public abstract class MediaBrowserServiceCompat extends android.app.Service {
+ ctor public MediaBrowserServiceCompat();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void attachToBaseContext(android.content.Context!);
+ method public void dump(java.io.FileDescriptor!, java.io.PrintWriter!, String![]!);
+ method public final android.os.Bundle! getBrowserRootHints();
+ method public final androidx.media.MediaSessionManager.RemoteUserInfo getCurrentBrowserInfo();
+ method public android.support.v4.media.session.MediaSessionCompat.Token? getSessionToken();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void notifyChildrenChanged(androidx.media.MediaSessionManager.RemoteUserInfo, String, android.os.Bundle);
+ method public void notifyChildrenChanged(String);
+ method public void notifyChildrenChanged(String, android.os.Bundle);
+ method public android.os.IBinder! onBind(android.content.Intent!);
+ method public void onCustomAction(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<android.os.Bundle!>);
+ method public abstract androidx.media.MediaBrowserServiceCompat.BrowserRoot? onGetRoot(String, int, android.os.Bundle?);
+ method public abstract void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+ method public void onLoadChildren(String, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>, android.os.Bundle);
+ method public void onLoadItem(String!, androidx.media.MediaBrowserServiceCompat.Result<android.support.v4.media.MediaBrowserCompat.MediaItem!>);
+ method public void onSearch(String, android.os.Bundle!, androidx.media.MediaBrowserServiceCompat.Result<java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem!>!>);
+ method public void setSessionToken(android.support.v4.media.session.MediaSessionCompat.Token!);
+ field public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
+ }
+
+ public static final class MediaBrowserServiceCompat.BrowserRoot {
+ ctor public MediaBrowserServiceCompat.BrowserRoot(String, android.os.Bundle?);
+ method public android.os.Bundle! getExtras();
+ method public String! getRootId();
+ field public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
+ field public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
+ field public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
+ field @Deprecated public static final String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
+ }
+
+ public static class MediaBrowserServiceCompat.Result<T> {
+ method public void detach();
+ method public void sendError(android.os.Bundle?);
+ method public void sendProgressUpdate(android.os.Bundle?);
+ method public void sendResult(T?);
+ }
+
+ public final class MediaSessionManager {
+ method public static androidx.media.MediaSessionManager getSessionManager(android.content.Context);
+ method public boolean isTrustedForMediaControl(androidx.media.MediaSessionManager.RemoteUserInfo);
+ }
+
+ public static final class MediaSessionManager.RemoteUserInfo {
+ ctor public MediaSessionManager.RemoteUserInfo(String, int, int);
+ method public String getPackageName();
+ method public int getPid();
+ method public int getUid();
+ field public static final String LEGACY_CONTROLLER = "android.media.session.MediaController";
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int UNKNOWN_PID = -1; // 0xffffffff
+ field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int UNKNOWN_UID = -1; // 0xffffffff
+ }
+
+ public abstract class VolumeProviderCompat {
+ ctor public VolumeProviderCompat(@androidx.media.VolumeProviderCompat.ControlType int, int, int);
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public VolumeProviderCompat(@androidx.media.VolumeProviderCompat.ControlType int, int, int, String?);
+ method public final int getCurrentVolume();
+ method public final int getMaxVolume();
+ method @androidx.media.VolumeProviderCompat.ControlType public final int getVolumeControl();
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final String? getVolumeControlId();
+ method public Object! getVolumeProvider();
+ method public void onAdjustVolume(int);
+ method public void onSetVolumeTo(int);
+ method public void setCallback(androidx.media.VolumeProviderCompat.Callback!);
+ method public final void setCurrentVolume(int);
+ field public static final int VOLUME_CONTROL_ABSOLUTE = 2; // 0x2
+ field public static final int VOLUME_CONTROL_FIXED = 0; // 0x0
+ field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
+ }
+
+ public abstract static class VolumeProviderCompat.Callback {
+ ctor public VolumeProviderCompat.Callback();
+ method public abstract void onVolumeChanged(androidx.media.VolumeProviderCompat!);
+ }
+
+ @IntDef({androidx.media.VolumeProviderCompat.VOLUME_CONTROL_FIXED, androidx.media.VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, androidx.media.VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface VolumeProviderCompat.ControlType {
+ }
+
+}
+
+package androidx.media.app {
+
+ public class NotificationCompat {
+ }
+
+ public static class NotificationCompat.DecoratedMediaCustomViewStyle extends androidx.media.app.NotificationCompat.MediaStyle {
+ ctor public NotificationCompat.DecoratedMediaCustomViewStyle();
+ }
+
+ public static class NotificationCompat.MediaStyle extends androidx.core.app.NotificationCompat.Style {
+ ctor public NotificationCompat.MediaStyle();
+ ctor public NotificationCompat.MediaStyle(androidx.core.app.NotificationCompat.Builder!);
+ method public static android.support.v4.media.session.MediaSessionCompat.Token! getMediaSession(android.app.Notification!);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setCancelButtonIntent(android.app.PendingIntent!);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setMediaSession(android.support.v4.media.session.MediaSessionCompat.Token!);
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public androidx.media.app.NotificationCompat.MediaStyle setRemotePlaybackInfo(CharSequence, @DrawableRes int, android.app.PendingIntent?);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setShowActionsInCompactView(int...);
+ method public androidx.media.app.NotificationCompat.MediaStyle! setShowCancelButton(boolean);
+ }
+
+}
+
+package androidx.media.session {
+
+ public class MediaButtonReceiver extends android.content.BroadcastReceiver {
+ ctor public MediaButtonReceiver();
+ method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, android.content.ComponentName!, long);
+ method public static android.app.PendingIntent! buildMediaButtonPendingIntent(android.content.Context!, long);
+ method public static android.view.KeyEvent! handleIntent(android.support.v4.media.session.MediaSessionCompat!, android.content.Intent!);
+ method @RequiresApi(31) protected void onForegroundServiceStartNotAllowedException(android.content.Intent, android.app.ForegroundServiceStartNotAllowedException);
+ method public void onReceive(android.content.Context!, android.content.Intent!);
+ }
+
+}
+
+package androidx.media.utils {
+
+ public final class MediaConstants {
+ field public static final String BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT = "androidx.media.utils.MediaBrowserCompat.extras.CUSTOM_BROWSER_ACTION_LIMIT";
+ field public static final String BROWSER_ROOT_HINTS_KEY_MEDIA_ART_SIZE_PIXELS = "android.media.extras.MEDIA_ART_SIZE_HINT_PIXELS";
+ field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_LIMIT";
+ field public static final String BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS = "androidx.media.MediaBrowserCompat.Extras.KEY_ROOT_CHILDREN_SUPPORTED_FLAGS";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.BrowserRoot.Extras.APPLICATION_PREFERENCES_USING_CAR_APP_LIBRARY_INTENT";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST = "androidx.media.utils.extras.CUSTOM_BROWSER_ACTION_ROOT_LIST";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_FAVORITES_MEDIA_ITEM = "androidx.media.BrowserRoot.Extras.FAVORITES_MEDIA_ITEM";
+ field public static final String BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED = "android.media.browse.SEARCH_SUPPORTED";
+ field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE = "androidx.media.MediaItem.Extras.COMPLETION_PERCENTAGE";
+ field public static final String DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS = "android.media.extra.PLAYBACK_STATUS";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE = "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE = "android.media.browse.CONTENT_STYLE_GROUP_TITLE_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE = "android.media.browse.CONTENT_STYLE_PLAYABLE_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM = "android.media.browse.CONTENT_STYLE_SINGLE_ITEM_HINT";
+ field public static final String DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST = "androidx.media.utils.extras.CUSTOM_BROWSER_ACTION_ID_LIST";
+ field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED = 2; // 0x2
+ field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED = 0; // 0x0
+ field public static final int DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED = 1; // 0x1
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM = 4; // 0x4
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM = 3; // 0x3
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM = 2; // 0x2
+ field public static final int DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM = 1; // 0x1
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_EXTRAS = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_EXTRAS";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_ICON_URI";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_ID";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_LABEL";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM";
+ field public static final String EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM = "androidx.media.utils.extras.KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM";
+ field public static final String METADATA_KEY_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_CONTENT_ID";
+ field public static final String METADATA_KEY_IS_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
+ field public static final String METADATA_KEY_IS_EXPLICIT = "android.media.IS_EXPLICIT";
+ field public static final String METADATA_KEY_NEXT_EPISODE_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_NEXT_EPISODE_CONTENT_ID";
+ field public static final String METADATA_KEY_SERIES_CONTENT_ID = "androidx.media.MediaMetadatCompat.METADATA_KEY_SERIES_CONTENT_ID";
+ field public static final long METADATA_VALUE_ATTRIBUTE_PRESENT = 1L; // 0x1L
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_INTENT = "android.media.extras.ERROR_RESOLUTION_ACTION_INTENT";
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_ACTION_LABEL = "android.media.extras.ERROR_RESOLUTION_ACTION_LABEL";
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT = "androidx.media.PlaybackStateCompat.Extras.ERROR_RESOLUTION_USING_CAR_APP_LIBRARY_INTENT";
+ field public static final String PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID = "androidx.media.PlaybackStateCompat.Extras.KEY_MEDIA_ID";
+ field public static final String SESSION_EXTRAS_KEY_ACCOUNT_NAME = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_NAME";
+ field public static final String SESSION_EXTRAS_KEY_ACCOUNT_TYPE = "androidx.media.MediaSessionCompat.Extras.KEY_ACCOUNT_TYPE";
+ field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_NEXT";
+ field public static final String SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV = "android.media.playback.ALWAYS_RESERVE_SPACE_FOR.ACTION_SKIP_TO_PREVIOUS";
+ field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_LEGACY_STREAM_TYPE = "android.media.session.extra.LEGACY_STREAM_TYPE";
+ field public static final String TRANSPORT_CONTROLS_EXTRAS_KEY_SHUFFLE = "androidx.media.MediaControllerCompat.TransportControls.extras.KEY_SHUFFLE";
+ }
+
+}
+
diff --git a/media/media/build.gradle b/media/media/build.gradle
index b1b873f..1523950 100644
--- a/media/media/build.gradle
+++ b/media/media/build.gradle
@@ -39,10 +39,6 @@
buildFeatures {
aidl = true
}
- lint {
- // Temporarily disabled due to flakiness (see b/291607684).
- disable "RequireUnstableAidlAnnotation"
- }
sourceSets {
main.java.srcDirs += [
]
diff --git a/media/media/lint-baseline.xml b/media/media/lint-baseline.xml
index de43ef9..de5add1 100644
--- a/media/media/lint-baseline.xml
+++ b/media/media/lint-baseline.xml
@@ -2,6 +2,96 @@
<issues format="6" by="lint 8.1.0-beta05" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.0-beta05)" variant="all" version="8.1.0-beta05">
<issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="oneway interface IMediaControllerCallback {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/android/support/v4/media/session/IMediaControllerCallback.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="interface IMediaSession {"
+ errorLine2="^">
+ <location
+ file="src/main/aidl/android/support/v4/media/session/IMediaSession.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable MediaDescriptionCompat;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/MediaDescriptionCompat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable MediaMetadataCompat;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/MediaMetadataCompat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable MediaSessionCompat.Token;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/session/MediaSessionCompat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable MediaSessionCompat.QueueItem;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/session/MediaSessionCompat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable MediaSessionCompat.ResultReceiverWrapper;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/session/MediaSessionCompat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable ParcelableVolumeInfo;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/session/ParcelableVolumeInfo.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable PlaybackStateCompat;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/session/PlaybackStateCompat.aidl"/>
+ </issue>
+
+ <issue
+ id="RequireUnstableAidlAnnotation"
+ message="Unstable AIDL files must be annotated with `@RequiresOptIn` marker"
+ errorLine1="@JavaOnlyStableParcelable parcelable RatingCompat;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/aidl/android/support/v4/media/RatingCompat.aidl"/>
+ </issue>
+
+ <issue
id="LambdaLast"
message="Functional interface parameters (such as parameter 1, "listener", in androidx.media.AudioFocusRequestCompat.Builder.setOnAudioFocusChangeListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
errorLine1=" @NonNull OnAudioFocusChangeListener listener, @NonNull Handler handler) {"
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
index 78683e9..88ba6cf 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
@@ -44,6 +44,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
@@ -158,6 +159,7 @@
* can return different sessions for different controllers.
*/
@Test
+ @Ignore("Flaky: b/291281118")
public void onGetSession_returnsDifferentSessions() {
final List<SessionToken> tokens = new ArrayList<>();
TestServiceRegistry.getInstance().setOnGetSessionHandler(
diff --git a/mediarouter/mediarouter/api/1.6.0-beta01.txt b/mediarouter/mediarouter/api/1.6.0-beta01.txt
index 00e0b0a..bc026c9 100644
--- a/mediarouter/mediarouter/api/1.6.0-beta01.txt
+++ b/mediarouter/mediarouter/api/1.6.0-beta01.txt
@@ -572,7 +572,7 @@
public final class RouteListingPreference {
method public java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!> getItems();
method public android.content.ComponentName? getLinkedItemComponentName();
- method public boolean getUseSystemOrdering();
+ method public boolean isSystemOrderingEnabled();
field public static final String ACTION_TRANSFER_MEDIA = "android.media.action.TRANSFER_MEDIA";
field public static final String EXTRA_ROUTE_ID = "android.media.extra.ROUTE_ID";
}
@@ -582,7 +582,7 @@
method public androidx.mediarouter.media.RouteListingPreference build();
method public androidx.mediarouter.media.RouteListingPreference.Builder setItems(java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!>);
method public androidx.mediarouter.media.RouteListingPreference.Builder setLinkedItemComponentName(android.content.ComponentName?);
- method public androidx.mediarouter.media.RouteListingPreference.Builder setUseSystemOrdering(boolean);
+ method public androidx.mediarouter.media.RouteListingPreference.Builder setSystemOrderingEnabled(boolean);
}
public static final class RouteListingPreference.Item {
diff --git a/mediarouter/mediarouter/api/current.ignore b/mediarouter/mediarouter/api/current.ignore
new file mode 100644
index 0000000..e3f190d
--- /dev/null
+++ b/mediarouter/mediarouter/api/current.ignore
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+AddedMethod: androidx.mediarouter.media.RouteListingPreference#isSystemOrderingEnabled():
+ Added method androidx.mediarouter.media.RouteListingPreference.isSystemOrderingEnabled()
+AddedMethod: androidx.mediarouter.media.RouteListingPreference.Builder#setSystemOrderingEnabled(boolean):
+ Added method androidx.mediarouter.media.RouteListingPreference.Builder.setSystemOrderingEnabled(boolean)
+
+
+RemovedMethod: androidx.mediarouter.media.RouteListingPreference#getUseSystemOrdering():
+ Removed method androidx.mediarouter.media.RouteListingPreference.getUseSystemOrdering()
+RemovedMethod: androidx.mediarouter.media.RouteListingPreference.Builder#setUseSystemOrdering(boolean):
+ Removed method androidx.mediarouter.media.RouteListingPreference.Builder.setUseSystemOrdering(boolean)
diff --git a/mediarouter/mediarouter/api/current.txt b/mediarouter/mediarouter/api/current.txt
index 00e0b0a..bc026c9 100644
--- a/mediarouter/mediarouter/api/current.txt
+++ b/mediarouter/mediarouter/api/current.txt
@@ -572,7 +572,7 @@
public final class RouteListingPreference {
method public java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!> getItems();
method public android.content.ComponentName? getLinkedItemComponentName();
- method public boolean getUseSystemOrdering();
+ method public boolean isSystemOrderingEnabled();
field public static final String ACTION_TRANSFER_MEDIA = "android.media.action.TRANSFER_MEDIA";
field public static final String EXTRA_ROUTE_ID = "android.media.extra.ROUTE_ID";
}
@@ -582,7 +582,7 @@
method public androidx.mediarouter.media.RouteListingPreference build();
method public androidx.mediarouter.media.RouteListingPreference.Builder setItems(java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!>);
method public androidx.mediarouter.media.RouteListingPreference.Builder setLinkedItemComponentName(android.content.ComponentName?);
- method public androidx.mediarouter.media.RouteListingPreference.Builder setUseSystemOrdering(boolean);
+ method public androidx.mediarouter.media.RouteListingPreference.Builder setSystemOrderingEnabled(boolean);
}
public static final class RouteListingPreference.Item {
diff --git a/mediarouter/mediarouter/api/restricted_1.6.0-beta01.txt b/mediarouter/mediarouter/api/restricted_1.6.0-beta01.txt
index 00e0b0a..bc026c9 100644
--- a/mediarouter/mediarouter/api/restricted_1.6.0-beta01.txt
+++ b/mediarouter/mediarouter/api/restricted_1.6.0-beta01.txt
@@ -572,7 +572,7 @@
public final class RouteListingPreference {
method public java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!> getItems();
method public android.content.ComponentName? getLinkedItemComponentName();
- method public boolean getUseSystemOrdering();
+ method public boolean isSystemOrderingEnabled();
field public static final String ACTION_TRANSFER_MEDIA = "android.media.action.TRANSFER_MEDIA";
field public static final String EXTRA_ROUTE_ID = "android.media.extra.ROUTE_ID";
}
@@ -582,7 +582,7 @@
method public androidx.mediarouter.media.RouteListingPreference build();
method public androidx.mediarouter.media.RouteListingPreference.Builder setItems(java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!>);
method public androidx.mediarouter.media.RouteListingPreference.Builder setLinkedItemComponentName(android.content.ComponentName?);
- method public androidx.mediarouter.media.RouteListingPreference.Builder setUseSystemOrdering(boolean);
+ method public androidx.mediarouter.media.RouteListingPreference.Builder setSystemOrderingEnabled(boolean);
}
public static final class RouteListingPreference.Item {
diff --git a/mediarouter/mediarouter/api/restricted_current.ignore b/mediarouter/mediarouter/api/restricted_current.ignore
new file mode 100644
index 0000000..e3f190d
--- /dev/null
+++ b/mediarouter/mediarouter/api/restricted_current.ignore
@@ -0,0 +1,11 @@
+// Baseline format: 1.0
+AddedMethod: androidx.mediarouter.media.RouteListingPreference#isSystemOrderingEnabled():
+ Added method androidx.mediarouter.media.RouteListingPreference.isSystemOrderingEnabled()
+AddedMethod: androidx.mediarouter.media.RouteListingPreference.Builder#setSystemOrderingEnabled(boolean):
+ Added method androidx.mediarouter.media.RouteListingPreference.Builder.setSystemOrderingEnabled(boolean)
+
+
+RemovedMethod: androidx.mediarouter.media.RouteListingPreference#getUseSystemOrdering():
+ Removed method androidx.mediarouter.media.RouteListingPreference.getUseSystemOrdering()
+RemovedMethod: androidx.mediarouter.media.RouteListingPreference.Builder#setUseSystemOrdering(boolean):
+ Removed method androidx.mediarouter.media.RouteListingPreference.Builder.setUseSystemOrdering(boolean)
diff --git a/mediarouter/mediarouter/api/restricted_current.txt b/mediarouter/mediarouter/api/restricted_current.txt
index 00e0b0a..bc026c9 100644
--- a/mediarouter/mediarouter/api/restricted_current.txt
+++ b/mediarouter/mediarouter/api/restricted_current.txt
@@ -572,7 +572,7 @@
public final class RouteListingPreference {
method public java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!> getItems();
method public android.content.ComponentName? getLinkedItemComponentName();
- method public boolean getUseSystemOrdering();
+ method public boolean isSystemOrderingEnabled();
field public static final String ACTION_TRANSFER_MEDIA = "android.media.action.TRANSFER_MEDIA";
field public static final String EXTRA_ROUTE_ID = "android.media.extra.ROUTE_ID";
}
@@ -582,7 +582,7 @@
method public androidx.mediarouter.media.RouteListingPreference build();
method public androidx.mediarouter.media.RouteListingPreference.Builder setItems(java.util.List<androidx.mediarouter.media.RouteListingPreference.Item!>);
method public androidx.mediarouter.media.RouteListingPreference.Builder setLinkedItemComponentName(android.content.ComponentName?);
- method public androidx.mediarouter.media.RouteListingPreference.Builder setUseSystemOrdering(boolean);
+ method public androidx.mediarouter.media.RouteListingPreference.Builder setSystemOrderingEnabled(boolean);
}
public static final class RouteListingPreference.Item {
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
index 4f37053..6f7b964 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
@@ -279,13 +279,13 @@
@UiThreadTest
public void testReset() {
assertNotNull(mRouter);
- assertNotNull(MediaRouter.getGlobalRouter());
+ assertNotNull(MediaRouter.sGlobal);
MediaRouterTestHelper.resetMediaRouter();
- assertNull(MediaRouter.getGlobalRouter());
+ assertNull(MediaRouter.sGlobal);
MediaRouter newInstance = MediaRouter.getInstance(mContext);
- assertNotNull(MediaRouter.getGlobalRouter());
+ assertNotNull(MediaRouter.sGlobal);
assertFalse(newInstance.getRoutes().isEmpty());
}
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/RouteListingPreferenceTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/RouteListingPreferenceTest.java
index e99c4e9..5bcc40d 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/RouteListingPreferenceTest.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/RouteListingPreferenceTest.java
@@ -93,7 +93,7 @@
new RouteListingPreference.Builder()
.setItems(Collections.singletonList(fakeRlpItem))
.setLinkedItemComponentName(FAKE_COMPONENT_NAME)
- .setUseSystemOrdering(false)
+ .setSystemOrderingEnabled(false)
.build();
android.media.RouteListingPreference platformRlp =
fakeRouteListingPreference.toPlatformRouteListingPreference();
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteChooserDialog.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteChooserDialog.java
index b18543e..e2f4e1f 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteChooserDialog.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/app/MediaRouteChooserDialog.java
@@ -19,7 +19,10 @@
import static androidx.mediarouter.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTED;
import static androidx.mediarouter.media.MediaRouter.RouteInfo.CONNECTION_STATE_CONNECTING;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -98,6 +101,7 @@
private ProgressBar mSearchingProgressBar;
private ListView mListView;
private RouteAdapter mAdapter;
+ private ScreenOnOffReceiver mScreenOnOffReceiver;
private boolean mAttachedToWindow;
private long mLastUpdateTime;
@@ -140,6 +144,7 @@
mRouter = MediaRouter.getInstance(context);
mCallback = new MediaRouterCallback();
+ mScreenOnOffReceiver = new ScreenOnOffReceiver();
}
/**
@@ -249,6 +254,27 @@
mListView.setEmptyView(findViewById(android.R.id.empty));
updateLayout();
+
+ registerBroadcastReceiver();
+ }
+
+ private void registerBroadcastReceiver() {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
+ getContext().registerReceiver(mScreenOnOffReceiver, filter);
+ }
+
+ @Override
+ public void dismiss() {
+ unregisterBroadcastReceiver();
+ super.dismiss();
+ }
+
+ private void unregisterBroadcastReceiver() {
+ try {
+ getContext().unregisterReceiver(mScreenOnOffReceiver);
+ } catch (IllegalArgumentException e) {
+ // May already be unregistered; ignore.
+ }
}
/**
@@ -563,4 +589,13 @@
return lhs.getName().compareToIgnoreCase(rhs.getName());
}
}
+
+ final class ScreenOnOffReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+ dismiss();
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
index 3091883..00c0ad0 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
@@ -142,10 +142,7 @@
*/
public static final int UNSELECT_REASON_ROUTE_CHANGED = 3;
- // Maintains global media router state for the process.
- // This field is initialized lazily when it is necessary.
- // Access this field directly only when you don't want to initialize it.
- // Use {@link #getGlobalRouter()} to get a valid instance.
+ /** Maintains global media router state for the process. */
static GlobalMediaRouter sGlobal;
// Context-bound state of the media router.
@@ -326,14 +323,14 @@
sGlobal = null;
}
- /**
- * Gets the initialized global router.
- */
+ /** Gets the initialized global router. */
+ @RestrictTo(LIBRARY_GROUP)
+ @NonNull
static GlobalMediaRouter getGlobalRouter() {
if (sGlobal == null) {
- return null;
+ throw new IllegalStateException(
+ "getGlobalRouter cannot be called when sGlobal is " + "null");
}
- sGlobal.ensureInitialized();
return sGlobal;
}
@@ -347,9 +344,7 @@
@NonNull
public List<RouteInfo> getRoutes() {
checkCallingThread();
- GlobalMediaRouter globalMediaRouter = getGlobalRouter();
- return globalMediaRouter == null ? Collections.emptyList() :
- globalMediaRouter.getRoutes();
+ return getGlobalRouter().getRoutes();
}
/**
@@ -362,9 +357,7 @@
@NonNull
public List<ProviderInfo> getProviders() {
checkCallingThread();
- GlobalMediaRouter globalMediaRouter = getGlobalRouter();
- return globalMediaRouter == null ? Collections.emptyList() :
- globalMediaRouter.getProviders();
+ return getGlobalRouter().getProviders();
}
/**
@@ -395,8 +388,7 @@
@Nullable
public RouteInfo getBluetoothRoute() {
checkCallingThread();
- GlobalMediaRouter globalMediaRouter = getGlobalRouter();
- return globalMediaRouter == null ? null : globalMediaRouter.getBluetoothRoute();
+ return getGlobalRouter().getBluetoothRoute();
}
/**
@@ -980,8 +972,7 @@
@Nullable
public MediaRouterParams getRouterParams() {
checkCallingThread();
- GlobalMediaRouter globalMediaRouter = getGlobalRouter();
- return globalMediaRouter == null ? null : globalMediaRouter.getRouterParams();
+ return getGlobalRouter().getRouterParams();
}
/**
@@ -1079,8 +1070,7 @@
* Returns whether transferring media from remote to local is enabled.
*/
static boolean isTransferToLocalEnabled() {
- GlobalMediaRouter globalMediaRouter = getGlobalRouter();
- return globalMediaRouter != null && globalMediaRouter.isTransferToLocalEnabled();
+ return getGlobalRouter().isTransferToLocalEnabled();
}
/**
@@ -1534,7 +1524,7 @@
}
checkCallingThread();
- for (IntentFilter intentFilter: mControlFilters) {
+ for (IntentFilter intentFilter : mControlFilters) {
if (intentFilter.hasCategory(category)) {
return true;
}
@@ -1572,7 +1562,7 @@
}
checkCallingThread();
- for (IntentFilter intentFilter: mControlFilters) {
+ for (IntentFilter intentFilter : mControlFilters) {
if (intentFilter.hasCategory(category) && intentFilter.hasAction(action)) {
return true;
}
@@ -1603,7 +1593,7 @@
checkCallingThread();
ContentResolver contentResolver = getGlobalRouter().getContentResolver();
- for (IntentFilter intentFilter: mControlFilters) {
+ for (IntentFilter intentFilter : mControlFilters) {
if (intentFilter.match(contentResolver, intent, true, TAG) >= 0) {
return true;
}
@@ -2264,7 +2254,7 @@
}
RouteInfo findRouteByDescriptorId(String id) {
- for (RouteInfo route: mRoutes) {
+ for (RouteInfo route : mRoutes) {
if (route.mDescriptorId.equals(id)) {
return route;
}
@@ -2561,7 +2551,6 @@
implements SystemMediaRouteProvider.SyncCallback,
RegisteredMediaRouteProviderWatcher.Callback {
final Context mApplicationContext;
- private boolean mIsInitialized;
SystemMediaRouteProvider mSystemProvider;
@VisibleForTesting
@@ -2625,27 +2614,15 @@
ActivityManagerCompat.isLowRamDevice(
(ActivityManager)
applicationContext.getSystemService(Context.ACTIVITY_SERVICE));
- }
- @SuppressLint({"NewApi", "SyntheticAccessor"})
- void ensureInitialized() {
- if (mIsInitialized) {
- return;
- }
- mIsInitialized = true;
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- mTransferReceiverDeclared = MediaTransferReceiver.isDeclared(mApplicationContext);
- } else {
- mTransferReceiverDeclared = false;
- }
-
- if (mTransferReceiverDeclared) {
- mMr2Provider = new MediaRoute2Provider(
- mApplicationContext, new Mr2ProviderCallback());
- } else {
- mMr2Provider = null;
- }
+ mTransferReceiverDeclared =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
+ && MediaTransferReceiver.isDeclared(mApplicationContext);
+ mMr2Provider =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && mTransferReceiverDeclared
+ ? new MediaRoute2Provider(
+ mApplicationContext, new Mr2ProviderCallback())
+ : null;
// Add the system media route provider for interoperating with
// the framework media router. This one is special and receives
@@ -2655,7 +2632,6 @@
}
private void start() {
- // Using lambda would break some apps.
mActiveScanThrottlingHelper =
new MediaRouterActiveScanThrottlingHelper(this::updateDiscoveryRequest);
addProvider(mSystemProvider, /* treatRouteDescriptorIdsAsUnique= */ true);
@@ -2671,15 +2647,13 @@
}
void reset() {
- if (!mIsInitialized) {
- return;
- }
- mRegisteredProviderWatcher.stop();
mActiveScanThrottlingHelper.reset();
setRouteListingPreference(null);
-
setMediaSessionCompat(null);
+
+ mRegisteredProviderWatcher.stop();
+
for (RemoteControlClientRecord record : mRemoteControlClients) {
record.disconnect();
}
@@ -3036,7 +3010,7 @@
}
// Notify providers.
- for (ProviderInfo providerInfo: mProviders) {
+ for (ProviderInfo providerInfo : mProviders) {
MediaRouteProvider provider = providerInfo.mProviderInstance;
if (provider == mMr2Provider) {
// MediaRoute2Provider is handled by updateMr2ProviderDiscoveryRequest().
@@ -3167,7 +3141,7 @@
}
private ProviderInfo findProviderInfo(MediaRouteProvider providerInstance) {
- for (ProviderInfo providerInfo: mProviders) {
+ for (ProviderInfo providerInfo : mProviders) {
if (providerInfo.mProviderInstance == providerInstance) {
return providerInfo;
}
@@ -3433,31 +3407,7 @@
&& route.mDescriptorId.equals(SystemMediaRouteProvider.DEFAULT_ROUTE_ID);
}
- void selectRouteInternal(@NonNull RouteInfo route,
- @UnselectReason int unselectReason) {
- // TODO: Remove the following logging when no longer needed.
- if (sGlobal == null || (mBluetoothRoute != null && route.isDefault())) {
- final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
- StringBuilder sb = new StringBuilder();
- // callStack[3] is the caller of this method.
- for (int i = 3; i < callStack.length; i++) {
- StackTraceElement caller = callStack[i];
- sb.append(caller.getClassName())
- .append(".")
- .append(caller.getMethodName())
- .append(":")
- .append(caller.getLineNumber())
- .append(" ");
- }
- if (sGlobal == null) {
- Log.w(TAG, "setSelectedRouteInternal is called while sGlobal is null: pkgName="
- + mApplicationContext.getPackageName() + ", callers=" + sb);
- } else {
- Log.w(TAG, "Default route is selected while a BT route is available: pkgName="
- + mApplicationContext.getPackageName() + ", callers=" + sb);
- }
- }
-
+ void selectRouteInternal(@NonNull RouteInfo route, @UnselectReason int unselectReason) {
if (mSelectedRoute == route) {
return;
}
@@ -3719,7 +3669,7 @@
mPlaybackInfo.volumeControlId = null;
}
- for (RemoteControlClientRecord remoteControlClientRecord: mRemoteControlClients) {
+ for (RemoteControlClientRecord remoteControlClientRecord : mRemoteControlClients) {
remoteControlClientRecord.updatePlaybackInfo();
}
if (mMediaSession != null) {
@@ -3832,32 +3782,30 @@
mVpCompat.setCurrentVolume(current);
} else {
// Otherwise create a new provider and update
- mVpCompat = new VolumeProviderCompat(controlType, max, current,
- volumeControlId) {
- @Override
- public void onSetVolumeTo(final int volume) {
- mCallbackHandler.post(new Runnable() {
+ mVpCompat =
+ new VolumeProviderCompat(
+ controlType, max, current, volumeControlId) {
@Override
- public void run() {
- if (mSelectedRoute != null) {
- mSelectedRoute.requestSetVolume(volume);
- }
+ public void onSetVolumeTo(final int volume) {
+ mCallbackHandler.post(
+ () -> {
+ if (mSelectedRoute != null) {
+ mSelectedRoute.requestSetVolume(volume);
+ }
+ });
}
- });
- }
- @Override
- public void onAdjustVolume(final int direction) {
- mCallbackHandler.post(new Runnable() {
@Override
- public void run() {
- if (mSelectedRoute != null) {
- mSelectedRoute.requestUpdateVolume(direction);
- }
+ public void onAdjustVolume(final int direction) {
+ mCallbackHandler.post(
+ () -> {
+ if (mSelectedRoute != null) {
+ mSelectedRoute.requestUpdateVolume(
+ direction);
+ }
+ });
}
- });
- }
- };
+ };
mMsCompat.setPlaybackToRemote(mVpCompat);
}
}
@@ -3982,9 +3930,8 @@
}
}
- final int callbackCount = mTempCallbackRecords.size();
- for (int i = 0; i < callbackCount; i++) {
- invokeCallback(mTempCallbackRecords.get(i), what, obj, arg);
+ for (CallbackRecord tempCallbackRecord : mTempCallbackRecords) {
+ invokeCallback(tempCallbackRecord, what, obj, arg);
}
} finally {
mTempCallbackRecords.clear();
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RouteListingPreference.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RouteListingPreference.java
index 9f9735b..5ea089f 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RouteListingPreference.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RouteListingPreference.java
@@ -73,13 +73,13 @@
public static final String EXTRA_ROUTE_ID = android.media.RouteListingPreference.EXTRA_ROUTE_ID;
@NonNull private final List<RouteListingPreference.Item> mItems;
- private final boolean mUseSystemOrdering;
+ private final boolean mIsSystemOrderingEnabled;
@Nullable private final ComponentName mLinkedItemComponentName;
// Must be package private to avoid a synthetic accessor for the builder.
/* package */ RouteListingPreference(RouteListingPreference.Builder builder) {
mItems = builder.mItems;
- mUseSystemOrdering = builder.mUseSystemOrdering;
+ mIsSystemOrderingEnabled = builder.mIsSystemOrderingEnabled;
mLinkedItemComponentName = builder.mLinkedItemComponentName;
}
@@ -100,8 +100,8 @@
* <p>The system's ordering strategy is implementation-dependent, but may take into account each
* route's recency or frequency of use in order to rank them.
*/
- public boolean getUseSystemOrdering() {
- return mUseSystemOrdering;
+ public boolean isSystemOrderingEnabled() {
+ return mIsSystemOrderingEnabled;
}
/**
@@ -134,13 +134,13 @@
}
RouteListingPreference that = (RouteListingPreference) other;
return mItems.equals(that.mItems)
- && mUseSystemOrdering == that.mUseSystemOrdering
+ && mIsSystemOrderingEnabled == that.mIsSystemOrderingEnabled
&& Objects.equals(mLinkedItemComponentName, that.mLinkedItemComponentName);
}
@Override
public int hashCode() {
- return Objects.hash(mItems, mUseSystemOrdering, mLinkedItemComponentName);
+ return Objects.hash(mItems, mIsSystemOrderingEnabled, mLinkedItemComponentName);
}
// Internal methods.
@@ -158,13 +158,13 @@
// The builder fields must be package private to avoid synthetic accessors.
/* package */ List<RouteListingPreference.Item> mItems;
- /* package */ boolean mUseSystemOrdering;
+ /* package */ boolean mIsSystemOrderingEnabled;
/* package */ ComponentName mLinkedItemComponentName;
/** Creates a new instance with default values (documented in the setters). */
public Builder() {
mItems = Collections.emptyList();
- mUseSystemOrdering = true;
+ mIsSystemOrderingEnabled = true;
}
/**
@@ -180,15 +180,14 @@
}
/**
- * See {@link #getUseSystemOrdering()}
+ * See {@link #isSystemOrderingEnabled()}
*
* <p>The default value is {@code true}.
*/
- // Lint requires "isUseSystemOrdering", but "getUseSystemOrdering" is a better name.
- @SuppressWarnings("MissingGetterMatchingBuilder")
@NonNull
- public RouteListingPreference.Builder setUseSystemOrdering(boolean useSystemOrdering) {
- mUseSystemOrdering = useSystemOrdering;
+ public RouteListingPreference.Builder setSystemOrderingEnabled(
+ boolean systemOrderingEnabled) {
+ mIsSystemOrderingEnabled = systemOrderingEnabled;
return this;
}
@@ -576,7 +575,7 @@
return new android.media.RouteListingPreference.Builder()
.setItems(platformRlpItems)
.setLinkedItemComponentName(routeListingPreference.getLinkedItemComponentName())
- .setUseSystemOrdering(routeListingPreference.getUseSystemOrdering())
+ .setUseSystemOrdering(routeListingPreference.isSystemOrderingEnabled())
.build();
}
diff --git a/playground-common/playground-plugin/build.gradle b/playground-common/playground-plugin/build.gradle
index 6012c6a..83996d6 100644
--- a/playground-common/playground-plugin/build.gradle
+++ b/playground-common/playground-plugin/build.gradle
@@ -20,8 +20,8 @@
}
dependencies {
- implementation("com.gradle:gradle-enterprise-gradle-plugin:3.12.4")
- implementation("com.gradle:common-custom-user-data-gradle-plugin:1.9")
+ implementation("com.gradle:gradle-enterprise-gradle-plugin:3.14.1")
+ implementation("com.gradle:common-custom-user-data-gradle-plugin:1.11.1")
testImplementation(libs.junit)
testImplementation(libs.truth)
}
diff --git a/privacysandbox/ads/ads-adservices/api/current.txt b/privacysandbox/ads/ads-adservices/api/current.txt
index 6a4905b..7af040f 100644
--- a/privacysandbox/ads/ads-adservices/api/current.txt
+++ b/privacysandbox/ads/ads-adservices/api/current.txt
@@ -100,20 +100,13 @@
package androidx.privacysandbox.ads.adservices.common {
public final class AdData {
- ctor public AdData(optional android.net.Uri renderUri, optional String metadata);
+ ctor public AdData(android.net.Uri renderUri, String metadata);
method public String getMetadata();
method public android.net.Uri getRenderUri();
property public final String metadata;
property public final android.net.Uri renderUri;
}
- @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static final class AdData.Builder {
- ctor public AdData.Builder();
- method public androidx.privacysandbox.ads.adservices.common.AdData build();
- method public androidx.privacysandbox.ads.adservices.common.AdData.Builder setMetadata(String metadata);
- method public androidx.privacysandbox.ads.adservices.common.AdData.Builder setRenderUri(android.net.Uri renderUri);
- }
-
public final class AdSelectionSignals {
ctor public AdSelectionSignals(String signals);
method public String getSignals();
@@ -198,20 +191,13 @@
}
public final class TrustedBiddingData {
- ctor public TrustedBiddingData(optional android.net.Uri trustedBiddingUri, optional java.util.List<java.lang.String> trustedBiddingKeys);
+ ctor public TrustedBiddingData(android.net.Uri trustedBiddingUri, java.util.List<java.lang.String> trustedBiddingKeys);
method public java.util.List<java.lang.String> getTrustedBiddingKeys();
method public android.net.Uri getTrustedBiddingUri();
property public final java.util.List<java.lang.String> trustedBiddingKeys;
property public final android.net.Uri trustedBiddingUri;
}
- @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static final class TrustedBiddingData.Builder {
- ctor public TrustedBiddingData.Builder();
- method public androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData build();
- method public androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData.Builder setTrustedBiddingKeys(java.util.List<java.lang.String> trustedBiddingKeys);
- method public androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData.Builder setTrustedBiddingUri(android.net.Uri trustedBiddingUri);
- }
-
}
package androidx.privacysandbox.ads.adservices.measurement {
diff --git a/privacysandbox/ads/ads-adservices/api/restricted_current.txt b/privacysandbox/ads/ads-adservices/api/restricted_current.txt
index 6a4905b..7af040f 100644
--- a/privacysandbox/ads/ads-adservices/api/restricted_current.txt
+++ b/privacysandbox/ads/ads-adservices/api/restricted_current.txt
@@ -100,20 +100,13 @@
package androidx.privacysandbox.ads.adservices.common {
public final class AdData {
- ctor public AdData(optional android.net.Uri renderUri, optional String metadata);
+ ctor public AdData(android.net.Uri renderUri, String metadata);
method public String getMetadata();
method public android.net.Uri getRenderUri();
property public final String metadata;
property public final android.net.Uri renderUri;
}
- @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static final class AdData.Builder {
- ctor public AdData.Builder();
- method public androidx.privacysandbox.ads.adservices.common.AdData build();
- method public androidx.privacysandbox.ads.adservices.common.AdData.Builder setMetadata(String metadata);
- method public androidx.privacysandbox.ads.adservices.common.AdData.Builder setRenderUri(android.net.Uri renderUri);
- }
-
public final class AdSelectionSignals {
ctor public AdSelectionSignals(String signals);
method public String getSignals();
@@ -198,20 +191,13 @@
}
public final class TrustedBiddingData {
- ctor public TrustedBiddingData(optional android.net.Uri trustedBiddingUri, optional java.util.List<java.lang.String> trustedBiddingKeys);
+ ctor public TrustedBiddingData(android.net.Uri trustedBiddingUri, java.util.List<java.lang.String> trustedBiddingKeys);
method public java.util.List<java.lang.String> getTrustedBiddingKeys();
method public android.net.Uri getTrustedBiddingUri();
property public final java.util.List<java.lang.String> trustedBiddingKeys;
property public final android.net.Uri trustedBiddingUri;
}
- @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static final class TrustedBiddingData.Builder {
- ctor public TrustedBiddingData.Builder();
- method public androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData build();
- method public androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData.Builder setTrustedBiddingKeys(java.util.List<java.lang.String> trustedBiddingKeys);
- method public androidx.privacysandbox.ads.adservices.customaudience.TrustedBiddingData.Builder setTrustedBiddingUri(android.net.Uri trustedBiddingUri);
- }
-
}
package androidx.privacysandbox.ads.adservices.measurement {
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/common/AdDataTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/common/AdDataTest.kt
index cc86a64..c140524 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/common/AdDataTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/common/AdDataTest.kt
@@ -17,10 +17,7 @@
package androidx.privacysandbox.ads.adservices.common
import android.net.Uri
-import android.os.Build
-import androidx.annotation.RequiresApi
import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth
import org.junit.Test
@@ -28,10 +25,10 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 33)
class AdDataTest {
private val uri: Uri = Uri.parse("abc.com")
private val metadata = "metadata"
+
@Test
fun testToString() {
val result = "AdData: renderUri=$uri, metadata='$metadata'"
@@ -45,14 +42,4 @@
var adData2 = AdData(Uri.parse("abc.com"), "metadata")
Truth.assertThat(adData1 == adData2).isTrue()
}
-
- @Test
- @RequiresApi(Build.VERSION_CODES.TIRAMISU)
- fun testBuilderSetters() {
- val constructed = AdData(uri, metadata)
- val builder = AdData.Builder()
- .setRenderUri(uri)
- .setMetadata(metadata)
- Truth.assertThat(builder.build()).isEqualTo(constructed)
- }
}
diff --git a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingDataTest.kt b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingDataTest.kt
index 5b74ef1..4cb9357 100644
--- a/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingDataTest.kt
+++ b/privacysandbox/ads/ads-adservices/src/androidTest/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingDataTest.kt
@@ -17,10 +17,7 @@
package androidx.privacysandbox.ads.adservices.customaudience
import android.net.Uri
-import android.os.Build
-import androidx.annotation.RequiresApi
import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth
import org.junit.Test
@@ -28,24 +25,14 @@
@SmallTest
@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = 33)
class TrustedBiddingDataTest {
private val uri = Uri.parse("abc.com")
private val keys = listOf("key1", "key2")
+
@Test
fun testToString() {
val result = "TrustedBiddingData: trustedBiddingUri=abc.com trustedBiddingKeys=[key1, key2]"
val trustedBiddingData = TrustedBiddingData(uri, keys)
Truth.assertThat(trustedBiddingData.toString()).isEqualTo(result)
}
-
- @RequiresApi(Build.VERSION_CODES.TIRAMISU)
- @Test
- fun testBuilderSetters() {
- val constructed = TrustedBiddingData(uri, keys)
- val builder = TrustedBiddingData.Builder()
- .setTrustedBiddingUri(uri)
- .setTrustedBiddingKeys(keys)
- Truth.assertThat(builder.build()).isEqualTo(constructed)
- }
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/common/AdData.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/common/AdData.kt
index a274659..c12afe8 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/common/AdData.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/common/AdData.kt
@@ -17,8 +17,6 @@
package androidx.privacysandbox.ads.adservices.common
import android.net.Uri
-import android.os.Build
-import androidx.annotation.RequiresApi
/**
* Represents data specific to an ad that is necessary for ad selection and rendering.
@@ -26,8 +24,8 @@
* @param metadata buyer ad metadata represented as a JSON string
*/
class AdData public constructor(
- val renderUri: Uri = Uri.EMPTY,
- val metadata: String = ""
+ val renderUri: Uri,
+ val metadata: String
) {
/** Checks whether two [AdData] objects contain the same information. */
@@ -49,42 +47,4 @@
override fun toString(): String {
return "AdData: renderUri=$renderUri, metadata='$metadata'"
}
-
- /** Builder for [AdData] objects. */
- @RequiresApi(Build.VERSION_CODES.TIRAMISU)
- public class Builder {
- private var renderUri: Uri = Uri.EMPTY
- private var metadata: String = ""
-
- /**
- * Sets the URI that points to the ad's rendering assets. The URI must use HTTPS.
- *
- * @param renderUri a URI pointing to the ad's rendering assets
- */
- fun setRenderUri(renderUri: Uri): Builder = apply {
- this.renderUri = renderUri
- }
-
- /**
- * Sets the buyer ad metadata used during the ad selection process.
- *
- * @param metadata The metadata should be a valid JSON object serialized as a string.
- * Metadata represents ad-specific bidding information that will be used during ad selection
- * as part of bid generation and used in buyer JavaScript logic, which is executed in an
- * isolated execution environment.
- *
- * If the metadata is not a valid JSON object that can be consumed by the buyer's JS, the
- * ad will not be eligible for ad selection.
- */
- fun setMetadata(metadata: String): Builder = apply {
- this.metadata = metadata
- }
-
- /**
- * Builds an instance of [AdData]
- */
- fun build(): AdData {
- return AdData(renderUri, metadata)
- }
- }
}
diff --git a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingData.kt b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingData.kt
index 077c397..64c7d67 100644
--- a/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingData.kt
+++ b/privacysandbox/ads/ads-adservices/src/main/java/androidx/privacysandbox/ads/adservices/customaudience/TrustedBiddingData.kt
@@ -17,8 +17,6 @@
package androidx.privacysandbox.ads.adservices.customaudience
import android.net.Uri
-import android.os.Build
-import androidx.annotation.RequiresApi
/**
* Represents data used during the ad selection process to fetch buyer bidding signals from a
@@ -31,8 +29,8 @@
* bidding signals.
*/
class TrustedBiddingData public constructor(
- val trustedBiddingUri: Uri = Uri.EMPTY,
- val trustedBiddingKeys: List<String> = emptyList()
+ val trustedBiddingUri: Uri,
+ val trustedBiddingKeys: List<String>
) {
/**
* @return `true` if two [TrustedBiddingData] objects contain the same information
@@ -55,38 +53,4 @@
return "TrustedBiddingData: trustedBiddingUri=$trustedBiddingUri " +
"trustedBiddingKeys=$trustedBiddingKeys"
}
-
- /** Builder for [TrustedBiddingData] objects. */
- @RequiresApi(Build.VERSION_CODES.TIRAMISU)
- public class Builder {
- private var trustedBiddingUri: Uri = Uri.EMPTY
- private var trustedBiddingKeys: List<String> = emptyList()
-
- /**
- * Sets the trusted Bidding Uri
- *
- * @param trustedBiddingUri the URI pointing to the trusted key-value server holding bidding
- * signals. The URI must use HTTPS.
- */
- fun setTrustedBiddingUri(trustedBiddingUri: Uri): Builder = apply {
- this.trustedBiddingUri = trustedBiddingUri
- }
-
- /**
- * Sets the trusted Bidding keys.
- *
- * @param trustedBiddingKeys list of keys to query the trusted key-value server with.
- * This list is permitted to be empty.
- */
- fun setTrustedBiddingKeys(trustedBiddingKeys: List<String>): Builder = apply {
- this.trustedBiddingKeys = trustedBiddingKeys
- }
-
- /**
- * Builds and instance of [TrustedBiddingData]
- */
- fun build(): TrustedBiddingData {
- return TrustedBiddingData(trustedBiddingUri, trustedBiddingKeys)
- }
- }
}
diff --git a/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt b/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt
index ea94188..2dcc31b 100644
--- a/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt
+++ b/privacysandbox/plugins/plugins-privacysandbox-library/src/main/java/androidx/privacysandboxlibraryplugin/PrivacySandboxLibraryPlugin.kt
@@ -85,7 +85,7 @@
)
add(
"implementation",
- "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3"
+ "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
)
add(
"implementation",
@@ -93,11 +93,11 @@
)
add(
"implementation",
- "androidx.privacysandbox.sdkruntime:sdkruntime-core:1.0.0-alpha01"
+ "androidx.privacysandbox.sdkruntime:sdkruntime-core:1.0.0-alpha06"
)
add(
"implementation",
- "androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha01"
+ "androidx.privacysandbox.sdkruntime:sdkruntime-client:1.0.0-alpha06"
)
}
project.afterEvaluate {
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
index 704d543..3c7ef5e 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
+++ b/privacysandbox/sdkruntime/sdkruntime-client/build.gradle
@@ -15,6 +15,7 @@
*/
import androidx.build.LibraryType
+import javax.inject.Inject
plugins {
id("AndroidXPlugin")
@@ -22,6 +23,72 @@
id("org.jetbrains.kotlin.android")
}
+abstract class BundleTestSdkDexTask extends DefaultTask {
+
+ @InputFiles
+ @PathSensitive(PathSensitivity.NAME_ONLY)
+ abstract ConfigurableFileCollection getTestSdkApkFolders()
+
+ @OutputDirectory
+ abstract DirectoryProperty getOutputDir()
+
+ @Inject
+ abstract FileSystemOperations getFileSystemOperations()
+
+ @Inject
+ abstract ArchiveOperations getArchiveOperations()
+
+ @TaskAction
+ def exec() {
+ for (File folder : testSdkApkFolders.files) {
+ for (File file : folder.listFiles()) {
+ String fileName = file.name
+ if (!fileName.endsWith(".apk")) {
+ continue
+ }
+
+ int projectNameEnd = fileName.indexOf("-")
+ String projectName = projectNameEnd > 0 ? fileName.substring(0, projectNameEnd) : fileName
+
+ fileSystemOperations.copy {
+ from(archiveOperations.zipTree(file))
+ into(outputDir.dir("test-sdks/$projectName/"))
+ include('*.dex')
+ }
+ }
+ }
+ }
+}
+
+def bundleTestSdkDexTaskProvider = tasks.register("bundleTestSdkDexTask", BundleTestSdkDexTask) {
+ description("Bundle DEX from the androidTestBundleDex configuration into assets folder")
+
+ def configuration = configurations.getByName("androidTestBundleDex")
+ testSdkApkFolders.from(configuration.incoming.artifactView {}.files)
+}
+
+androidComponents {
+ onVariants(selector().withBuildType("debug")) {
+ androidTest.sources.assets.addGeneratedSourceDirectory(
+ bundleTestSdkDexTaskProvider,
+ BundleTestSdkDexTask::getOutputDir
+ )
+ }
+}
+
+configurations {
+ androidTestBundleDex {
+ canBeConsumed = false
+ canBeResolved = true
+ attributes {
+ attribute(
+ LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
+ objects.named(LibraryElements, "testSdkApk")
+ )
+ }
+ }
+}
+
dependencies {
api(libs.kotlinStdlib)
api(libs.kotlinCoroutinesCore)
@@ -48,6 +115,8 @@
androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation(libs.dexmakerMockitoInline, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+
+ androidTestBundleDex(project(":privacysandbox:sdkruntime:test-sdks:current"))
}
android {
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt
index 4149ac0..09f256a 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/loader/LocalSdkProviderTest.kt
@@ -19,7 +19,6 @@
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
-import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.privacysandbox.sdkruntime.client.EmptyActivity
import androidx.privacysandbox.sdkruntime.client.TestActivityHolder
@@ -31,7 +30,6 @@
import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
import androidx.privacysandbox.sdkruntime.core.SandboxedSdkInfo
-import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
import androidx.privacysandbox.sdkruntime.core.Versions
import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
@@ -227,60 +225,6 @@
assertThat(controller.sdkActivityHandlers[token]).isNull()
}
- class CurrentVersionProviderLoadTest : SandboxedSdkProviderCompat() {
- @JvmField
- var onLoadSdkBinder: Binder? = null
-
- @JvmField
- var lastOnLoadSdkParams: Bundle? = null
-
- @JvmField
- var isBeforeUnloadSdkCalled = false
-
- @Throws(LoadSdkCompatException::class)
- override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
- val result = CurrentVersionSdkTest(context!!)
- onLoadSdkBinder = result
-
- lastOnLoadSdkParams = params
- if (params.getBoolean("needFail", false)) {
- throw LoadSdkCompatException(RuntimeException(), params)
- }
- return SandboxedSdkCompat(result)
- }
-
- override fun beforeUnloadSdk() {
- isBeforeUnloadSdkCalled = true
- }
-
- override fun getView(
- windowContext: Context,
- params: Bundle,
- width: Int,
- height: Int
- ): View {
- return View(windowContext)
- }
- }
-
- @Suppress("unused") // Reflection calls
- internal class CurrentVersionSdkTest(
- private val context: Context
- ) : Binder() {
- fun getSandboxedSdks(): List<SandboxedSdkCompat> =
- SdkSandboxControllerCompat.from(context).getSandboxedSdks()
-
- fun getAppOwnedSdkSandboxInterfaces(): List<AppOwnedSdkSandboxInterfaceCompat> =
- SdkSandboxControllerCompat.from(context).getAppOwnedSdkSandboxInterfaces()
-
- fun registerSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat): IBinder =
- SdkSandboxControllerCompat.from(context).registerSdkSandboxActivityHandler(handler)
-
- fun unregisterSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat) {
- SdkSandboxControllerCompat.from(context).unregisterSdkSandboxActivityHandler(handler)
- }
- }
-
internal class TestClassLoaderFactory(
private val testStorage: TestLocalSdkStorage
) : SdkLoader.ClassLoaderFactory {
@@ -364,35 +308,23 @@
)
}
- // add SDK loaded from test sources
+ val currentVersionSdk = TestSdkInfo(
+ Versions.API_VERSION,
+ "test-sdks/current/classes.dex",
+ "androidx.privacysandbox.sdkruntime.testsdk.current.CompatProvider"
+ )
val controller = TestStubController()
+
+ val loadedSdk = loadTestSdkFromAssets(currentVersionSdk.localSdkConfig, controller)
+ assertThat(loadedSdk.extractApiVersion())
+ .isEqualTo(currentVersionSdk.apiVersion)
+
add(
arrayOf(
- "BuiltFromSource",
- Versions.API_VERSION,
+ currentVersionSdk.localSdkConfig.dexPaths[0],
+ currentVersionSdk.apiVersion,
controller,
- loadTestSdkFromSource(controller),
- )
- )
- }
-
- private fun loadTestSdkFromSource(controller: TestStubController): LocalSdkProvider {
- val sdkLoader = SdkLoader(
- object : SdkLoader.ClassLoaderFactory {
- override fun createClassLoaderFor(
- sdkConfig: LocalSdkConfig,
- parent: ClassLoader
- ): ClassLoader = javaClass.classLoader!!
- },
- ApplicationProvider.getApplicationContext(),
- controller
- )
-
- return sdkLoader.loadSdk(
- LocalSdkConfig(
- packageName = "test.CurrentVersionProviderLoadTest",
- dexPaths = emptyList(),
- entryPoint = CurrentVersionProviderLoadTest::class.java.name
+ loadedSdk
)
)
}
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
index e08530e..2d2d2a7 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SandboxedSdkContextCompat.kt
@@ -224,6 +224,9 @@
val targetBaseDataDir = Api24.dataDir(baseContext)
val targetSharedPreferencesDir = File(targetBaseDataDir, "shared_prefs")
+ if (!targetSharedPreferencesDir.exists()) {
+ targetSharedPreferencesDir.mkdir()
+ }
if (sourceSharedPreferencesDir == targetSharedPreferencesDir) {
return true
diff --git a/privacysandbox/sdkruntime/test-sdks/current/build.gradle b/privacysandbox/sdkruntime/test-sdks/current/build.gradle
new file mode 100644
index 0000000..c69ab15
--- /dev/null
+++ b/privacysandbox/sdkruntime/test-sdks/current/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.android.build.api.artifact.SingleArtifact
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+ id("org.jetbrains.kotlin.android")
+}
+
+android {
+ namespace "androidx.privacysandbox.sdkruntime.testsdk.current"
+}
+
+dependencies {
+ implementation(project(":privacysandbox:sdkruntime:sdkruntime-core"))
+}
+
+/*
+ * Allow integration tests to consume the APK produced by this project
+ */
+configurations {
+ testSdkApk {
+ canBeConsumed = true
+ canBeResolved = false
+ attributes {
+ attribute(
+ LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
+ objects.named(LibraryElements, "testSdkApk")
+ )
+ }
+ }
+}
+
+androidComponents {
+ beforeVariants(selector().all()) { enabled = buildType == 'release' }
+ onVariants(selector().all().withBuildType("release"), { variant ->
+ artifacts {
+ testSdkApk(variant.artifacts.get(SingleArtifact.APK.INSTANCE))
+ }
+ })
+}
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/test-sdks/current/src/main/AndroidManifest.xml b/privacysandbox/sdkruntime/test-sdks/current/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8de5974
--- /dev/null
+++ b/privacysandbox/sdkruntime/test-sdks/current/src/main/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/test-sdks/current/src/main/java/androidx/privacysandbox/sdkruntime/testsdk/current/CompatProvider.kt b/privacysandbox/sdkruntime/test-sdks/current/src/main/java/androidx/privacysandbox/sdkruntime/testsdk/current/CompatProvider.kt
new file mode 100644
index 0000000..03f31ea
--- /dev/null
+++ b/privacysandbox/sdkruntime/test-sdks/current/src/main/java/androidx/privacysandbox/sdkruntime/testsdk/current/CompatProvider.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.privacysandbox.sdkruntime.testsdk.current
+
+import android.content.Context
+import android.os.Binder
+import android.os.Bundle
+import android.os.IBinder
+import android.view.View
+import androidx.privacysandbox.sdkruntime.core.AppOwnedSdkSandboxInterfaceCompat
+import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkProviderCompat
+import androidx.privacysandbox.sdkruntime.core.activity.SdkSandboxActivityHandlerCompat
+import androidx.privacysandbox.sdkruntime.core.controller.SdkSandboxControllerCompat
+
+@Suppress("unused") // Reflection usage from tests in privacysandbox:sdkruntime:sdkruntime-client
+class CompatProvider : SandboxedSdkProviderCompat() {
+ @JvmField
+ var onLoadSdkBinder: Binder? = null
+
+ @JvmField
+ var lastOnLoadSdkParams: Bundle? = null
+
+ @JvmField
+ var isBeforeUnloadSdkCalled = false
+
+ @Throws(LoadSdkCompatException::class)
+ override fun onLoadSdk(params: Bundle): SandboxedSdkCompat {
+ val result = CurrentVersionSdkTest(context!!)
+ onLoadSdkBinder = result
+
+ lastOnLoadSdkParams = params
+ if (params.getBoolean("needFail", false)) {
+ throw LoadSdkCompatException(RuntimeException(), params)
+ }
+ return SandboxedSdkCompat(result)
+ }
+
+ override fun beforeUnloadSdk() {
+ isBeforeUnloadSdkCalled = true
+ }
+
+ override fun getView(
+ windowContext: Context,
+ params: Bundle,
+ width: Int,
+ height: Int
+ ): View {
+ return View(windowContext)
+ }
+
+ internal class CurrentVersionSdkTest(
+ private val context: Context
+ ) : Binder() {
+ fun getSandboxedSdks(): List<SandboxedSdkCompat> =
+ SdkSandboxControllerCompat.from(context).getSandboxedSdks()
+
+ fun getAppOwnedSdkSandboxInterfaces(): List<AppOwnedSdkSandboxInterfaceCompat> =
+ SdkSandboxControllerCompat.from(context).getAppOwnedSdkSandboxInterfaces()
+
+ fun registerSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat): IBinder =
+ SdkSandboxControllerCompat.from(context).registerSdkSandboxActivityHandler(handler)
+
+ fun unregisterSdkSandboxActivityHandler(handler: SdkSandboxActivityHandlerCompat) {
+ SdkSandboxControllerCompat.from(context).unregisterSdkSandboxActivityHandler(handler)
+ }
+ }
+}
diff --git a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt
index f545175..19cb68b 100644
--- a/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt
+++ b/privacysandbox/ui/ui-client/src/androidTest/java/androidx/privacysandbox/ui/client/test/SandboxedSdkViewTest.kt
@@ -452,6 +452,28 @@
assertThat(testSandboxedUiAdapter.inputToken).isEqualTo(token)
}
+ /**
+ * Ensures that ACTIVE will only be sent to registered state change listeners after the first
+ * draw event.
+ */
+ @Test
+ fun activeStateOnlySentAfterFirstDraw() {
+ addViewToLayout()
+ var latch = CountDownLatch(1)
+ view.addStateChangedListener {
+ if (it == SandboxedSdkUiSessionState.Active) {
+ latch.countDown()
+ }
+ }
+ assertThat(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isTrue()
+
+ // Manually set state to IDLE.
+ // Subsequent draw events should not flip the state back to ACTIVE.
+ view.stateListenerManager.currentUiSessionState = SandboxedSdkUiSessionState.Idle
+ latch = CountDownLatch(1)
+ assertThat(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)).isFalse()
+ }
+
private fun addViewToLayout() {
activity.runOnUiThread {
activity.findViewById<LinearLayout>(
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt
index 0b6b31c..b3d581a 100644
--- a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt
+++ b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/view/SandboxedSdkView.kt
@@ -24,6 +24,7 @@
import android.view.SurfaceView
import android.view.View
import android.view.ViewGroup
+import android.view.ViewTreeObserver
import androidx.annotation.RequiresApi
import androidx.privacysandbox.ui.core.SandboxedUiAdapter
import java.util.concurrent.CopyOnWriteArrayList
@@ -61,7 +62,7 @@
/**
* There is an open session with the supplied [SandboxedUiAdapter] and its UI is currently
- * being displayed.
+ * being displayed. This state is set after the first draw event of the [SandboxedSdkView].
*/
object Active : SandboxedSdkUiSessionState()
@@ -132,6 +133,10 @@
/**
* Sets the Z-ordering of the [SandboxedSdkView]'s surface, relative to its window.
+ *
+ * When [setOnTop] is true, every [android.view.MotionEvent] on the [SandboxedSdkView] will be
+ * sent to the UI provider. When [setOnTop] is false, every [android.view.MotionEvent] will be
+ * sent to the client. By default, motion events are sent to the UI provider.
*/
fun setZOrderOnTopAndEnableUserInteraction(setOnTop: Boolean) {
if (setOnTop == isZOrderOnTop) return
@@ -211,7 +216,25 @@
} else {
super.addView(contentView, 0, contentView.layoutParams)
}
- stateListenerManager.currentUiSessionState = SandboxedSdkUiSessionState.Active
+ // Listen for first draw event before sending an ACTIVE state change to listeners. Removes
+ // the listener afterwards so that we don't handle multiple draw events.
+ viewTreeObserver.addOnDrawListener(
+ object : ViewTreeObserver.OnDrawListener {
+ var handledDraw = false
+
+ override fun onDraw() {
+ if (!handledDraw) {
+ stateListenerManager.currentUiSessionState =
+ SandboxedSdkUiSessionState.Active
+ post {
+ // Posted to handler as this can't be directly called from onDraw
+ viewTreeObserver.removeOnDrawListener(this)
+ }
+ handledDraw = true
+ }
+ }
+ }
+ )
}
internal fun onClientClosedSession(error: Throwable? = null) {
diff --git a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
index 5bd2008..1acb8cc 100644
--- a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
+++ b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
@@ -150,8 +150,11 @@
}
override fun notifyResized(width: Int, height: Int) {
- surfaceControlViewHost.relayout(width, height)
- session.notifyResized(width, height)
+ val mHandler = Handler(Looper.getMainLooper())
+ mHandler.post {
+ surfaceControlViewHost.relayout(width, height)
+ session.notifyResized(width, height)
+ }
}
override fun close() {
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt
index 6a10b3d..c10f74d 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewSmoothScrollToPositionTest.kt
@@ -158,12 +158,19 @@
"onStop should be called eventually",
calledOnStop.await(30, TimeUnit.SECONDS)
)
- Assert.assertNotNull(
- "smoothScrollToPosition should succeed " +
- "(first visible item: " + layoutManager.findFirstVisibleItemPosition() +
- ", last visible item: " + layoutManager.findLastVisibleItemPosition() + ")",
- recyclerView.findViewHolderForLayoutPosition(targetPosition)
- )
+
+ // This needs to be run on the UI thread 1) due to inspecting the results of operations
+ // (such as layout) that may occur after the latch is counted down, and 2) in order to
+ // ensure that it doesn't run concurrently with operations on the UI thread that might
+ // affect the state.
+ mActivityTestRule.runOnUiThread {
+ Assert.assertNotNull(
+ "smoothScrollToPosition should succeed " +
+ "(first visible item: " + layoutManager.findFirstVisibleItemPosition() +
+ ", last visible item: " + layoutManager.findLastVisibleItemPosition() + ")",
+ recyclerView.findViewHolderForLayoutPosition(targetPosition)
+ )
+ }
}
private fun setup(
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt
index 5753602..426a4f9 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/MusicDao.kt
@@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+@file:Suppress("DEPRECATION") // For @MapInfo
+
package androidx.room.integration.kotlintestapp.dao
import androidx.collection.ArrayMap
@@ -22,6 +25,7 @@
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
+import androidx.room.MapColumn
import androidx.room.MapInfo
import androidx.room.Query
import androidx.room.RawQuery
@@ -374,4 +378,42 @@
@Transaction
@Query("SELECT * FROM Playlist WHERE mPlaylistId = :id")
fun getPlaylistsWithSongsFlow(id: Int): Flow<PlaylistWithSongs>
+
+ @Query("SELECT * FROM Artist JOIN Song ON Artist.mArtistName = Song.mArtist")
+ @RewriteQueriesToDropUnusedColumns
+ fun artistNameToSongsMapColumn():
+ Map<@MapColumn(columnName = "mArtistName") String,
+ List<@MapColumn(columnName = "mReleasedYear") Int>>
+
+ @Query(
+ """
+ SELECT * FROM Image
+ LEFT JOIN Artist ON Image.mArtistInImage = Artist.mArtistName
+ LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist
+ LEFT JOIN Song ON Album.mAlbumName = Song.mAlbum
+ """
+ )
+ @RewriteQueriesToDropUnusedColumns
+ fun getImageYearToArtistToAlbumsToSongsMapColumn():
+ Map<@MapColumn(columnName = "mImageYear") Long, Map<Artist,
+ Map<@MapColumn(columnName = "mAlbumName") String, List<Song>>>>
+
+ @Query(
+ """
+ SELECT * FROM Image
+ LEFT JOIN Artist ON Image.mArtistInImage = Artist.mArtistName
+ LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist
+ LEFT JOIN Song ON Album.mAlbumName = Song.mAlbum
+ """
+ )
+ @RewriteQueriesToDropUnusedColumns
+ fun getImageYearToArtistToAlbumsToSongsMultiMapColumn():
+ Map<Image, Map<Artist, Map<@MapColumn(columnName = "mAlbumName") String,
+ List<@MapColumn(columnName = "mReleasedYear") Int>>>>
+
+ @RawQuery
+ @RewriteQueriesToDropUnusedColumns
+ fun getImageYearToArtistToAlbumsToSongsMultiMapColumn(query: SupportSQLiteQuery):
+ Map<Image, Map<Artist, Map<@MapColumn(columnName = "mAlbumName") String,
+ List<@MapColumn(columnName = "mReleasedYear") Int>>>>
}
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt
index 3647b62..b11a259 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/AmbiguousColumnResolverTest.kt
@@ -24,7 +24,7 @@
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.Insert
-import androidx.room.MapInfo
+import androidx.room.MapColumn
import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.Relation
@@ -103,7 +103,7 @@
}
@Test
- fun withMapInfo() {
+ fun withMapColumn() {
dao.getUserIdAndComments().let { userIdAndComments ->
assertThat(userIdAndComments[1]).containsExactly(comment1)
assertThat(userIdAndComments[2]).containsExactly(comment2, comment3)
@@ -198,32 +198,31 @@
// Suppress on CURSOR_MISMATCH is because @RewriteQueriesToDropUnusedColumns does not
// rewrite queries with duplicate columns.
@Suppress(RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT)
- @MapInfo(keyColumn = "id", keyTable = "User")
@Query("SELECT * FROM User JOIN Comment ON User.id = Comment.userId")
- fun getUserIdAndComments(): Map<Int, List<Comment>>
+ fun getUserIdAndComments(): Map<@MapColumn("id") Int, List<Comment>>
// This works because User.id is in the projection first, but if swapped with Comment.*
// it would return bad results, hence the AMBIGUOUS_COLUMN_IN_RESULT.
@Suppress(RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT)
- @MapInfo(keyColumn = "id", keyTable = "User")
@Query("SELECT User.id, Comment.* FROM User JOIN Comment ON User.id = Comment.userId")
- fun getUserIdAndCommentsTableOrderSwapped(): Map<Int, List<Comment>>
+ fun getUserIdAndCommentsTableOrderSwapped():
+ Map<@MapColumn("id") Int, List<Comment>>
// Aliasing the single ambiguous column is good.
- @MapInfo(keyColumn = "user_id")
@Query("""
SELECT Comment.*, User.id as user_id
FROM User JOIN Comment ON User.id = Comment.userId
""")
- fun getUserIdAliasedAndCommentsTableOrderSwapped(): Map<Int, List<Comment>>
+ fun getUserIdAliasedAndCommentsTableOrderSwapped():
+ Map<@MapColumn("user_id")Int, List<Comment>>
- @MapInfo(keyColumn = "id", keyTable = "User", valueColumn = "commentsCount")
@Query("""
SELECT User.id, count(*) AS commentsCount
FROM User JOIN Comment ON User.id = Comment.userId
GROUP BY User.id
""")
- fun getUserIdAndAmountOfComments(): Map<Int, Int>
+ fun getUserIdAndAmountOfComments():
+ Map<@MapColumn("id") Int, @MapColumn("commentsCount") Int>
@Query("SELECT * FROM User LEFT JOIN Comment ON User.id = Comment.userId")
fun getLeftJoinUserCommentMap(): Map<User, List<Comment>>
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt
index c44486f..6310e19 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/MultimapQueryTest.kt
@@ -59,6 +59,9 @@
/**
* Tests multimap return type for JOIN statements.
+ *
+ * Deprecation has been suppressed for @MapInfo. We still need these tests, but the annotation
+ * is deprecated.
*/
@MediumTest
@RunWith(AndroidJUnit4::class)
@@ -1334,6 +1337,176 @@
).isEmpty()
}
+ @Test
+ fun testDoubleNestedMapWithMapColumnKeyLeftJoin() {
+ mMusicDao.addArtists(mRhcp, mAcDc, mPinkFloyd)
+ mMusicDao.addAlbums(
+ mStadiumArcadium,
+ mCalifornication,
+ mTheDarkSideOfTheMoon,
+ mHighwayToHell,
+ mDreamland
+ )
+ mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mRhcpSong3)
+ mMusicDao.addImages(mPinkFloydAlbumCover, mRhcpAlbumCover, mTheClashAlbumCover)
+
+ val doubleNestedMap = mMusicDao.getImageYearToArtistToAlbumsToSongsMultiMapColumn()
+ val rhcpImageMap = doubleNestedMap.getValue(mRhcpAlbumCover)
+ val rhcpMap = rhcpImageMap.getValue(mRhcp)
+ val stadiumArcadiumList = rhcpMap[mStadiumArcadium.mAlbumName]
+ val californicationList = rhcpMap[mCalifornication.mAlbumName]
+
+ val stadiumArcadiumExpectedList = listOf(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+ val californicationExpectedList = listOf(mRhcpSong3.mReleasedYear)
+
+ assertThat(doubleNestedMap.keys).containsExactlyElementsIn(
+ listOf(
+ mPinkFloydAlbumCover,
+ mRhcpAlbumCover,
+ mTheClashAlbumCover
+ )
+ )
+ assertThat(rhcpImageMap.keys).containsExactly(mRhcp)
+ assertThat(rhcpMap.keys).containsExactlyElementsIn(
+ listOf(mCalifornication.mAlbumName, mStadiumArcadium.mAlbumName)
+ )
+ assertThat(stadiumArcadiumList).containsExactlyElementsIn(stadiumArcadiumExpectedList)
+ assertThat(californicationList).containsExactlyElementsIn(californicationExpectedList)
+
+ // LEFT JOIN Checks
+ assertThat(doubleNestedMap).containsKey(mTheClashAlbumCover)
+ assertThat(doubleNestedMap[mTheClashAlbumCover]).isEmpty()
+ assertThat(doubleNestedMap).containsKey(mPinkFloydAlbumCover)
+ assertThat(doubleNestedMap[mPinkFloydAlbumCover]).containsKey(mPinkFloyd)
+ assertThat(doubleNestedMap[mPinkFloydAlbumCover]!![mPinkFloyd])
+ .containsKey(mTheDarkSideOfTheMoon.mAlbumName)
+ assertThat(
+ doubleNestedMap[mPinkFloydAlbumCover]
+ !![mPinkFloyd]
+ !![mTheDarkSideOfTheMoon.mAlbumName]
+ ).isEmpty()
+ }
+
+ @Test
+ fun testDoubleNestedMapWithMapColumnKeyLeftJoinRawQuery() {
+ mMusicDao.addArtists(mRhcp, mAcDc, mPinkFloyd)
+ mMusicDao.addAlbums(
+ mStadiumArcadium,
+ mCalifornication,
+ mTheDarkSideOfTheMoon,
+ mHighwayToHell,
+ mDreamland
+ )
+ mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mRhcpSong3)
+ mMusicDao.addImages(mPinkFloydAlbumCover, mRhcpAlbumCover, mTheClashAlbumCover)
+
+ val doubleNestedMap = mMusicDao.getImageYearToArtistToAlbumsToSongsMultiMapColumn(
+ SimpleSQLiteQuery(
+ """
+ SELECT * FROM Image
+ LEFT JOIN Artist ON Image.mArtistInImage = Artist.mArtistName
+ LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist
+ LEFT JOIN Song ON Album.mAlbumName = Song.mAlbum
+ """
+ )
+ )
+ val rhcpImageMap = doubleNestedMap.getValue(mRhcpAlbumCover)
+ val rhcpMap = rhcpImageMap.getValue(mRhcp)
+ val stadiumArcadiumList = rhcpMap[mStadiumArcadium.mAlbumName]
+ val californicationList = rhcpMap[mCalifornication.mAlbumName]
+
+ val stadiumArcadiumExpectedList = listOf(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+ val californicationExpectedList = listOf(mRhcpSong3.mReleasedYear)
+
+ assertThat(doubleNestedMap.keys).containsExactlyElementsIn(
+ listOf(
+ mPinkFloydAlbumCover,
+ mRhcpAlbumCover,
+ mTheClashAlbumCover
+ )
+ )
+ assertThat(rhcpImageMap.keys).containsExactly(mRhcp)
+ assertThat(rhcpMap.keys).containsExactlyElementsIn(
+ listOf(mCalifornication.mAlbumName, mStadiumArcadium.mAlbumName)
+ )
+ assertThat(stadiumArcadiumList).containsExactlyElementsIn(stadiumArcadiumExpectedList)
+ assertThat(californicationList).containsExactlyElementsIn(californicationExpectedList)
+
+ // LEFT JOIN Checks
+ assertThat(doubleNestedMap).containsKey(mTheClashAlbumCover)
+ assertThat(doubleNestedMap[mTheClashAlbumCover]).isEmpty()
+ assertThat(doubleNestedMap).containsKey(mPinkFloydAlbumCover)
+ assertThat(doubleNestedMap[mPinkFloydAlbumCover]).containsKey(mPinkFloyd)
+ assertThat(doubleNestedMap[mPinkFloydAlbumCover]!![mPinkFloyd])
+ .containsKey(mTheDarkSideOfTheMoon.mAlbumName)
+ assertThat(
+ doubleNestedMap[mPinkFloydAlbumCover]
+ !![mPinkFloyd]
+ !![mTheDarkSideOfTheMoon.mAlbumName]
+ ).isEmpty()
+ }
+
+ @Test
+ fun testStringToListOfSongsMapColumn() {
+ mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mPinkFloydSong1)
+ mMusicDao.addArtists(mRhcp, mAcDc, mTheClash, mPinkFloyd)
+ val artistNameToSongsMap: Map<String, List<Int>> = mMusicDao.artistNameToSongsMapColumn()
+ assertThat(artistNameToSongsMap.containsKey("Pink Floyd")).isTrue()
+ assertThat(artistNameToSongsMap["Red Hot Chili Peppers"]).containsExactlyElementsIn(
+ listOf(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+ )
+ }
+
+ @Test
+ fun testDoubleNestedMapWithOneMapColumn() {
+ mMusicDao.addArtists(mRhcp, mAcDc, mPinkFloyd)
+ mMusicDao.addAlbums(
+ mStadiumArcadium,
+ mCalifornication,
+ mTheDarkSideOfTheMoon,
+ mHighwayToHell,
+ mDreamland
+ )
+ mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mRhcpSong3)
+ mMusicDao.addImages(mPinkFloydAlbumCover, mRhcpAlbumCover, mTheClashAlbumCover)
+
+ val doubleNestedMap = mMusicDao.getImageYearToArtistToAlbumsToSongsMapColumn()
+ val rhcpImageMap = doubleNestedMap.getValue(mRhcpAlbumCover.mImageYear)
+ val rhcpMap = rhcpImageMap.getValue(mRhcp)
+ val stadiumArcadiumList = rhcpMap.getValue("Stadium Arcadium")
+ val californicationList = rhcpMap.getValue("Californication")
+
+ val stadiumArcadiumExpectedList = listOf(mRhcpSong1, mRhcpSong2)
+ val californicationExpectedList = listOf(mRhcpSong3)
+
+ assertThat(doubleNestedMap.keys).containsExactlyElementsIn(
+ listOf(
+ mPinkFloydAlbumCover.mImageYear,
+ mRhcpAlbumCover.mImageYear,
+ mTheClashAlbumCover.mImageYear
+ )
+ )
+ assertThat(rhcpImageMap.keys).containsExactly(mRhcp)
+ assertThat(rhcpMap.keys).containsExactlyElementsIn(
+ listOf("Stadium Arcadium", "Californication")
+ )
+ assertThat(stadiumArcadiumList).containsExactlyElementsIn(stadiumArcadiumExpectedList)
+ assertThat(californicationList).containsExactlyElementsIn(californicationExpectedList)
+
+ // LEFT JOIN Checks
+ assertThat(doubleNestedMap).containsKey(mTheClashAlbumCover.mImageYear)
+ assertThat(doubleNestedMap[mTheClashAlbumCover.mImageYear]).isEmpty()
+ assertThat(doubleNestedMap).containsKey(mPinkFloydAlbumCover.mImageYear)
+ assertThat(doubleNestedMap[mPinkFloydAlbumCover.mImageYear]).containsKey(mPinkFloyd)
+ assertThat(doubleNestedMap[mPinkFloydAlbumCover.mImageYear]!![mPinkFloyd])
+ .containsKey(mTheDarkSideOfTheMoon.mAlbumName)
+ assertThat(
+ doubleNestedMap[mPinkFloydAlbumCover.mImageYear]
+ !![mPinkFloyd]
+ !![mTheDarkSideOfTheMoon.mAlbumName]
+ ).isEmpty()
+ }
+
/**
* Checks that the contents of the map are as expected.
*
diff --git a/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt b/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt
index 14344bb..f735c1e 100644
--- a/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTestWithKspGenKotlin/java/androidx/room/integration/kotlintestapp/test/ValueClassConverterWrapperTest.kt
@@ -214,7 +214,8 @@
assertThrows<IllegalStateException> {
db.dao().insertNullableEntity(data)
}.hasMessageThat().isEqualTo(
- "Cannot bind nullable value of inline class to a NOT NULL column."
+ "Cannot bind NULLABLE value 'data' of inline class 'NullableValue' to " +
+ "a NOT NULL column."
)
}
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java
index 6f74a64..2b344fe 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/MusicDao.java
@@ -22,6 +22,7 @@
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
+import androidx.room.MapColumn;
import androidx.room.MapInfo;
import androidx.room.Query;
import androidx.room.RawQuery;
@@ -46,14 +47,14 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
+import io.reactivex.Flowable;
+
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import io.reactivex.Flowable;
-
@Dao
@SuppressWarnings("ROOM_EXPAND_PROJECTION_WITH_UNUSED_COLUMNS")
public interface MusicDao {
@@ -198,114 +199,142 @@
getAllArtistAndTheirSongsAsLiveDataGuavaImmutableListMultimap();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation")
@MapInfo(keyColumn = "mArtistName")
@Query("SELECT * FROM Artist JOIN Song ON Artist.mArtistName = Song.mArtist")
Map<String, List<Song>> getArtistNameToSongs();
@RewriteQueriesToDropUnusedColumns
+ @Query("SELECT * FROM Artist JOIN Song ON Artist.mArtistName = Song.mArtist")
+ Map<@MapColumn(columnName = "mArtistName") String,
+ List<@MapColumn(columnName = "mReleasedYear") Integer>> getArtistNameToSongsMapColumn();
+
+ @RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mReleasedYear", valueColumn = "mReleasedYear")
@Query("SELECT * FROM Album JOIN Song ON Song.mReleasedYear = Album.mAlbumReleaseYear")
Map<Integer, List<Song>> getReleaseYearToAlbums();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mImageYear")
@Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
LongSparseArray<Artist> getAllAlbumCoverYearToArtistsWithLongSparseArray();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mImageYear")
@Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
SparseArrayCompat<Artist> getAllAlbumCoverYearToArtistsWithIntSparseArray();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mReleasedYear", valueColumn = "mTitle")
@Query("SELECT * FROM Album JOIN Song ON Song.mReleasedYear = Album.mAlbumReleaseYear")
Map<Integer, List<String>> getReleaseYearToSongNames();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mArtistName", valueColumn = "mArtist")
@RawQuery
Map<String, List<Song>> getArtistNameToSongsRawQuery(SupportSQLiteQuery query);
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mReleasedYear", valueColumn = "mReleasedYear")
@RawQuery
Map<Integer, List<Song>> getReleaseYearToAlbumsRawQuery(SupportSQLiteQuery query);
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mReleasedYear", valueColumn = "mTitle")
@RawQuery
Map<Integer, List<String>> getReleaseYearToSongNamesRawQuery(SupportSQLiteQuery query);
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(valueColumn = "songCount")
@Query("SELECT *, COUNT(mSongId) as songCount FROM Artist JOIN Song ON Artist.mArtistName = "
+ "Song.mArtist GROUP BY mArtistName")
Map<Artist, Integer> getArtistAndSongCountMap();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(valueColumn = "songCount")
@RawQuery
Map<Artist, Integer> getArtistAndSongCountMapRawQuery(SupportSQLiteQuery query);
// Other Map Key/Value Types
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(valueColumn = "mAlbumCover")
@Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
ImmutableMap<Artist, ByteBuffer> getAllArtistsWithAlbumCovers();
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(valueColumn = "mAlbumCover")
@RawQuery
ImmutableMap<Artist, ByteBuffer> getAllArtistsWithAlbumCoversRawQuery(SupportSQLiteQuery query);
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(valueColumn = "mImageYear")
@Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
ImmutableMap<Artist, Long> getAllArtistsWithAlbumCoverYear();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(valueColumn = "mImageYear")
@Query("SELECT * FROM Artist JOIN Image ON Artist.mArtistName = Image.mArtistInImage")
ArrayMap<Artist, Long> getAllArtistsWithAlbumCoverYearArrayMap();
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mImageYear")
@RawQuery
ImmutableMap<Long, Artist> getAllAlbumCoverYearToArtistsWithRawQuery(SupportSQLiteQuery query);
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mImageYear")
@RawQuery
ArrayMap<Long, Artist> getAllAlbumCoverYearToArtistsWithRawQueryArrayMap(
SupportSQLiteQuery query
);
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mAlbumCover", valueColumn = "mIsActive")
@Query("SELECT * FROM Image JOIN Artist ON Artist.mArtistName = Image.mArtistInImage")
ImmutableMap<ByteBuffer, Boolean> getAlbumCoversWithBandActivity();
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mAlbumCover", valueColumn = "mIsActive")
@RawQuery
ImmutableMap<ByteBuffer, Boolean> getAlbumCoversWithBandActivityRawQuery(
SupportSQLiteQuery query
);
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mDateReleased", valueColumn = "mIsActive")
@Query("SELECT * FROM Image JOIN Artist ON Artist.mArtistName = Image.mArtistInImage")
ImmutableMap<Date, Boolean> getAlbumDateWithBandActivity();
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mDateReleased", valueColumn = "mIsActive")
@RawQuery
ImmutableMap<Date, Boolean> getAlbumDateWithBandActivityRawQuery(SupportSQLiteQuery query);
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mFormat", valueColumn = "mIsActive")
@Query("SELECT * FROM Image JOIN Artist ON Artist.mArtistName = Image.mArtistInImage")
ImmutableMap<ImageFormat, Boolean> getImageFormatWithBandActivity();
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "mFormat", valueColumn = "mIsActive")
@RawQuery
ImmutableMap<ImageFormat, Boolean> getImageFormatWithBandActivityRawQuery(
SupportSQLiteQuery query
);
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(keyColumn = "dog", valueColumn = "cat")
@RawQuery
Map<Artist, Integer> getMapWithInvalidColumnRawQuery(SupportSQLiteQuery query);
@@ -320,6 +349,7 @@
ImmutableListMultimap<Artist, Album> getArtistAndAlbumsLeftJoinGuava();
@RewriteQueriesToDropUnusedColumns
+ @SuppressWarnings("deprecation") // for MapInfo
@MapInfo(valueColumn = "mAlbumName")
@Query("SELECT * FROM Artist LEFT JOIN Album ON Artist.mArtistName = Album.mAlbumArtist")
Map<Artist, List<String>> getArtistAndAlbumNamesLeftJoin();
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java
index d045d02..6fd554c 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/MultimapQueryTest.java
@@ -53,6 +53,8 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
+import io.reactivex.Flowable;
+
import org.hamcrest.MatcherAssert;
import org.junit.Before;
import org.junit.Rule;
@@ -70,8 +72,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import io.reactivex.Flowable;
-
/**
* Tests multimap return type for JOIN statements.
*/
@@ -765,6 +765,18 @@
}
@Test
+ public void testStringToListOfSongsMapColumn() {
+ mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mPinkFloydSong1);
+ mMusicDao.addArtists(mRhcp, mAcDc, mTheClash, mPinkFloyd);
+
+ Map<String, List<Integer>> artistNameToSongsMap = mMusicDao.getArtistNameToSongsMapColumn();
+ assertThat(artistNameToSongsMap.containsKey("Pink Floyd")).isTrue();
+ assertThat(artistNameToSongsMap.get("Red Hot Chili Peppers")).containsExactlyElementsIn(
+ Arrays.asList(mRhcpSong1.mReleasedYear, mRhcpSong2.mReleasedYear)
+ );
+ }
+
+ @Test
public void testIntegerToListOfAlbums() {
mMusicDao.addSongs(mRhcpSong1, mRhcpSong2, mAcdcSong1, mPinkFloydSong1);
mMusicDao.addAlbums(
diff --git a/room/room-common/api/current.txt b/room/room-common/api/current.txt
index 95d009b..612c15f 100644
--- a/room/room-common/api/current.txt
+++ b/room/room-common/api/current.txt
@@ -263,15 +263,22 @@
property public abstract kotlin.reflect.KClass<?> value;
}
- @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
- method public abstract String keyColumn() default "";
- method public abstract String keyTable() default "";
- method public abstract String valueColumn() default "";
- method public abstract String valueTable() default "";
- property public abstract String keyColumn;
- property public abstract String keyTable;
- property public abstract String valueColumn;
- property public abstract String valueTable;
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.TYPE) public @interface MapColumn {
+ method public abstract String columnName();
+ method public abstract String tableName() default "";
+ property public abstract String columnName;
+ property public abstract String tableName;
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
+ method @Deprecated public abstract String keyColumn() default "";
+ method @Deprecated public abstract String keyTable() default "";
+ method @Deprecated public abstract String valueColumn() default "";
+ method @Deprecated public abstract String valueTable() default "";
+ property @Deprecated public abstract String keyColumn;
+ property @Deprecated public abstract String keyTable;
+ property @Deprecated public abstract String valueColumn;
+ property @Deprecated public abstract String valueTable;
}
@IntDef({androidx.room.OnConflictStrategy.Companion.NONE, androidx.room.OnConflictStrategy.Companion.REPLACE, androidx.room.OnConflictStrategy.Companion.ROLLBACK, androidx.room.OnConflictStrategy.Companion.ABORT, androidx.room.OnConflictStrategy.Companion.FAIL, androidx.room.OnConflictStrategy.Companion.IGNORE}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface OnConflictStrategy {
diff --git a/room/room-common/api/restricted_current.txt b/room/room-common/api/restricted_current.txt
index 85cc4ca..474272c 100644
--- a/room/room-common/api/restricted_current.txt
+++ b/room/room-common/api/restricted_current.txt
@@ -263,15 +263,22 @@
property public abstract kotlin.reflect.KClass<?> value;
}
- @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
- method public abstract String keyColumn() default "";
- method public abstract String keyTable() default "";
- method public abstract String valueColumn() default "";
- method public abstract String valueTable() default "";
- property public abstract String keyColumn;
- property public abstract String keyTable;
- property public abstract String valueColumn;
- property public abstract String valueTable;
+ @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.TYPE) public @interface MapColumn {
+ method public abstract String columnName();
+ method public abstract String tableName() default "";
+ property public abstract String columnName;
+ property public abstract String tableName;
+ }
+
+ @Deprecated @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=kotlin.annotation.AnnotationTarget.FUNCTION) public @interface MapInfo {
+ method @Deprecated public abstract String keyColumn() default "";
+ method @Deprecated public abstract String keyTable() default "";
+ method @Deprecated public abstract String valueColumn() default "";
+ method @Deprecated public abstract String valueTable() default "";
+ property @Deprecated public abstract String keyColumn;
+ property @Deprecated public abstract String keyTable;
+ property @Deprecated public abstract String valueColumn;
+ property @Deprecated public abstract String valueTable;
}
@IntDef({androidx.room.OnConflictStrategy.Companion.NONE, androidx.room.OnConflictStrategy.Companion.REPLACE, androidx.room.OnConflictStrategy.Companion.ROLLBACK, androidx.room.OnConflictStrategy.Companion.ABORT, androidx.room.OnConflictStrategy.Companion.FAIL, androidx.room.OnConflictStrategy.Companion.IGNORE}) @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface OnConflictStrategy {
diff --git a/room/room-common/src/main/java/androidx/room/MapColumn.kt b/room/room-common/src/main/java/androidx/room/MapColumn.kt
new file mode 100644
index 0000000..423c6c4
--- /dev/null
+++ b/room/room-common/src/main/java/androidx/room/MapColumn.kt
@@ -0,0 +1,67 @@
+/*
+ * 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
+
+/**
+ * Declares which column is used to build a map or multimap return value in a [Dao]
+ * query method.
+ *
+ * This annotation is required when the key or value of a Map (or nested map) is a single column of
+ * one of the built in types (primitives, boxed primitives, enum, String, byte[], ByteBuffer) or
+ * a type with a converter (e.g. Date, UUID, etc).
+ *
+ * The use of this annotation provides clarity on which column should be used in retrieving
+ * information required by the return type.
+ *
+ * Example:
+ *
+ * ```
+ * @Query("SELECT * FROM Artist JOIN Song ON Artist.artistName = Song.artist")
+ * fun getArtistNameToSongNames():
+ * Map<@MapColumn(columnName = "artistName") String,
+ * @MapColumn(columnName = "songName") List<String>>
+ *
+ * @Query("SELECT *, COUNT(mSongId) as songCount FROM Artist JOIN Song ON
+ * Artist.artistName = Song.artist GROUP BY artistName")
+ * fun getArtistAndSongCounts(): Map<Artist, @MapColumn(columnName = "songCount") Integer>
+ * ```
+ *
+ * Column(s) specified in the provided @MapColumn annotation must be present in the query result.
+ */
+@Target(AnnotationTarget.TYPE)
+@Retention(AnnotationRetention.BINARY)
+public annotation class MapColumn(
+ /**
+ * The name of the column to be used for the map's key or value.
+ *
+ * @return The column name.
+ */
+ val columnName: String,
+
+ /**
+ * The name of the table or alias to be used for the map's column.
+ *
+ * Providing this value is optional. Useful for disambiguating between duplicate column names.
+ * For example, consider the following query:
+ * `SELECT * FROM Artist AS a JOIN Song AS s ON a.id == s.artistId`, then the `@MapColumn`
+ * for a return type `Map<String, List<Song>>` would be
+ * `Map<@MapColumn(columnName = "id", tableName = "a") String, List<Song>>`.
+ *
+ * @return The column table name.
+ */
+ val tableName: String = "",
+)
diff --git a/room/room-common/src/main/java/androidx/room/MapInfo.kt b/room/room-common/src/main/java/androidx/room/MapInfo.kt
index 526f949..93a0aeb 100644
--- a/room/room-common/src/main/java/androidx/room/MapInfo.kt
+++ b/room/room-common/src/main/java/androidx/room/MapInfo.kt
@@ -17,7 +17,7 @@
package androidx.room
/**
- * Declares which column(s) are used to build a map or multimap return value in a {@link Dao}
+ * Declares which column(s) are used to build a map or multimap return value in a [Dao]
* query method.
*
* This annotation is required when the key or value of the Map is a single column of one of the
@@ -46,6 +46,7 @@
*/
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
+@Deprecated("Use @MapColumn instead.")
public annotation class MapInfo(
/**
* The name of the column to be used for the map's keys.
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
index ca01837..f72cec5 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotated.kt
@@ -16,6 +16,7 @@
package androidx.room.compiler.processing
+import androidx.room.compiler.codegen.XClassName
import com.squareup.javapoet.ClassName
import kotlin.reflect.KClass
@@ -39,6 +40,21 @@
}
/**
+ * Returns the list of [XAnnotation] elements that have the same qualified name as the given
+ * [annotationName]. Otherwise, returns an empty list.
+ *
+ * For repeated annotations declared in Java code, please use the repeated annotation type,
+ * not the container. Calling this method with a container annotation will have inconsistent
+ * behaviour between Java AP and KSP.
+ *
+ * @see [hasAnnotation]
+ * @see [hasAnnotationWithPackage]
+ */
+ fun getAnnotations(annotationName: XClassName): List<XAnnotation> {
+ return getAllAnnotations().filter { annotationName.canonicalName == it.qualifiedName }
+ }
+
+ /**
* Gets the list of annotations with the given type.
*
* For repeated annotations declared in Java code, please use the repeated annotation type,
@@ -89,6 +105,16 @@
}
/**
+ * Returns `true` if this element is annotated with an [XAnnotation] that has the same
+ * qualified name as the given [annotationName].
+ *
+ * @see [hasAnyAnnotation]
+ */
+ fun hasAnnotation(annotationName: XClassName): Boolean {
+ return getAnnotations(annotationName).isNotEmpty()
+ }
+
+ /**
* Returns `true` if this element has an annotation that is declared in the given package.
* Alternatively, all annotations can be accessed with [getAllAnnotations].
*/
@@ -160,6 +186,18 @@
}
/**
+ * Returns the [XAnnotation] that has the same qualified name as [annotationName].
+ * Otherwise, `null` value is returned.
+ *
+ * @see [hasAnnotation]
+ * @see [getAnnotations]
+ * @see [hasAnnotationWithPackage]
+ */
+ fun getAnnotation(annotationName: XClassName): XAnnotation? {
+ return getAnnotations(annotationName).firstOrNull()
+ }
+
+ /**
* Returns the [Annotation]s that are annotated with [annotationName]
*/
fun getAnnotationsAnnotatedWith(
@@ -171,6 +209,17 @@
}
/**
+ * Returns the [Annotation]s that are annotated with [annotationName]
+ */
+ fun getAnnotationsAnnotatedWith(
+ annotationName: XClassName
+ ): Set<XAnnotation> {
+ return getAllAnnotations().filter {
+ it.type.typeElement?.hasAnnotation(annotationName) ?: false
+ }.toSet()
+ }
+
+ /**
* Returns the [XAnnotation] that has the same qualified name as [annotationName].
*
* @see [hasAnnotation]
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
index a0e190e..3df0f9f 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
@@ -74,6 +74,9 @@
/** All values declared in the annotation class. */
val annotationValues: List<XAnnotationValue>
+ /** All default values declared in the annotation class. */
+ val defaultValues: List<XAnnotationValue>
+
/** Returns the value of the given [methodName] as a type reference. */
fun getAsType(methodName: String): XType = getAnnotationValue(methodName).asType()
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
index 843368a..03b17bf 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
@@ -108,10 +108,18 @@
fun XVariableElement.toJavac(): VariableElement = (this as JavacVariableElement).element
@JvmStatic
- fun XAnnotation.toJavac(): AnnotationMirror = (this as JavacAnnotation).mirror
+ fun XAnnotation.toJavac(): AnnotationMirror = when (this) {
+ is JavacAnnotation -> this.mirror
+ // TODO(kuanyingchou: Try to support JavacKmAnnotation
+ else -> error("Don't know how to convert element of type '${this::class}' to Java")
+ }
@JvmStatic
- fun XAnnotationValue.toJavac(): AnnotationValue = (this as JavacAnnotationValue).annotationValue
+ fun XAnnotationValue.toJavac(): AnnotationValue = when (this) {
+ is JavacAnnotationValue -> this.annotationValue
+ // TODO(kuanyingchou: Try to support JavacKmAnnotationValue
+ else -> error("Don't know how to convert element of type '${this::class}' to Java")
+ }
@JvmStatic
fun XType.toJavac(): TypeMirror = (this as JavacType).typeMirror
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt
index a1cd205..1582a0e 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotation.kt
@@ -21,7 +21,6 @@
import androidx.room.compiler.processing.XAnnotationValue
import androidx.room.compiler.processing.XNullability
import androidx.room.compiler.processing.XType
-import androidx.room.compiler.processing.compat.XConverters.toXProcessing
import com.google.auto.common.AnnotationMirrors
import com.google.auto.common.MoreTypes
import javax.lang.model.element.AnnotationMirror
@@ -49,10 +48,23 @@
annotationValues.filter { explicitValues.contains(it.name) }
}
+ override val defaultValues: List<XAnnotationValue> by lazy {
+ annotationValues.mapNotNull {
+ val method = (it as JavacAnnotationValue).method
+ method.element.getDefaultValue()?.let { value ->
+ JavacAnnotationValue(env, method, value)
+ }
+ }
+ }
+
override val annotationValues: List<XAnnotationValue> by lazy {
AnnotationMirrors.getAnnotationValuesWithDefaults(mirror)
.map { (executableElement, annotationValue) ->
- annotationValue.toXProcessing(executableElement, env)
+ JavacAnnotationValue(
+ env,
+ env.wrapExecutableElement(executableElement) as JavacMethodElement,
+ annotationValue
+ )
}
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
index c4eb412..fb9cdaa 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
@@ -31,7 +31,7 @@
internal class JavacAnnotationValue(
val env: JavacProcessingEnv,
- private val method: JavacMethodElement,
+ val method: JavacMethodElement,
val annotationValue: AnnotationValue,
override val valueType: XType = method.returnType,
private val valueProvider: () -> Any? = {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
index 0d041a0..e3e5a57 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacConstructorElement.kt
@@ -83,6 +83,7 @@
}
override val kotlinMetadata: KmConstructorContainer? by lazy {
- (enclosingElement as? JavacTypeElement)?.kotlinMetadata?.getConstructorMetadata(element)
+ (enclosingElement as? JavacTypeElement)?.kotlinMetadata
+ ?.getConstructorMetadata(element)
}
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
index cdf34b6..356b357 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacExecutableElement.kt
@@ -29,7 +29,7 @@
abstract override val kotlinMetadata: KmFunctionContainer?
override val jvmDescriptor by lazy {
- element.descriptor()
+ element.descriptor(env.delegate)
}
abstract override val parameters: List<JavacMethodParameter>
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt
index ca1d5da..a0d9c1c 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacFieldElement.kt
@@ -28,6 +28,10 @@
env: JavacProcessingEnv,
element: VariableElement
) : JavacVariableElement(env, element), XFieldElement {
+
+ override val name: String
+ get() = (kotlinMetadata?.name ?: super.name)
+
override fun getAllAnnotations(): List<XAnnotation> {
return buildList {
addAll(super.getAllAnnotations())
@@ -48,7 +52,7 @@
}
override val kotlinMetadata: KmPropertyContainer? by lazy {
- (enclosingElement as? JavacTypeElement)?.kotlinMetadata?.getPropertyMetadata(name)
+ (enclosingElement as? JavacTypeElement)?.kotlinMetadata?.getPropertyMetadata(element)
}
private val syntheticMethodForAnnotations: JavacMethodElement? by lazy {
@@ -68,7 +72,7 @@
get() = enclosingElement
override val jvmDescriptor: String
- get() = element.descriptor()
+ get() = element.descriptor(env.delegate)
override val getter: XMethodElement? by lazy {
kotlinMetadata?.getter?.let { getterMetadata ->
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
index ac34870..023311f 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
@@ -43,21 +43,32 @@
override val type: XType
get() = typeElement.type
- // KmAnnotation doesn't include arguments with default values
override val declaredAnnotationValues: List<XAnnotationValue> by lazy {
- annotationValues
+ methodToDeclaredAnnotationValues.values.filterNotNull()
}
override val annotationValues: List<XAnnotationValue> by lazy {
+ methodToDeclaredAnnotationValues.mapNotNull { (method, annotationValue) ->
+ annotationValue ?: method.defaultValue
+ }
+ }
+
+ private val methodToDeclaredAnnotationValues:
+ Map<JavacMethodElement, XAnnotationValue?> by lazy {
val methods = typeElement.getDeclaredMethods()
- // KmAnnotation doesn't include arguments with default values
- methods
- .mapNotNull { method ->
+ val kmAnnotationArguments = kmAnnotation.getArguments(env)
+ methods.associateWith { method ->
+ // KmAnnotation doesn't include arguments with default values
+ kmAnnotationArguments[method.jvmName]?.let {
JavacKmAnnotationValue(
method = method,
- kmAnnotationArgumentContainer =
- kmAnnotation.getArguments(env)[method.jvmName] ?: return@mapNotNull null
+ kmAnnotationArgumentContainer = it
)
}
+ }
+ }
+
+ override val defaultValues: List<XAnnotationValue> by lazy {
+ typeElement.getDeclaredMethods().mapNotNull { it.defaultValue }
}
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt
index 3a3fcfa..4f87074 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodElement.kt
@@ -99,6 +99,10 @@
)
}
+ val defaultValue: JavacAnnotationValue? = element.defaultValue?.let {
+ JavacAnnotationValue(env, this, element.defaultValue, returnType)
+ }
+
override fun asMemberOf(other: XType): XMethodType {
return if (other !is JavacDeclaredType || enclosingElement.type.isSameType(other)) {
executableType
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
index 8c78886..66c3ea0 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacMethodParameter.kt
@@ -51,9 +51,14 @@
override val kotlinMetadata by lazy { kotlinMetadataFactory() }
override val name: String
- get() = (kotlinMetadata?.name ?: super.name).sanitizeAsJavaParameterName(
- argIndex = argIndex
- )
+ get() = if (isReceiverParam() && enclosingElement.isAbstract()) {
+ // Receiver parameter names for abstract methods are not reliable across different
+ // versions of KAPT so we just build the name ourselves to match KSP.
+ // https://youtrack.jetbrains.com/issue/KT-18048/kapt-drops-method-parameter-names
+ "\$this\$${enclosingElement.name}"
+ } else {
+ (kotlinMetadata?.name ?: super.name)
+ }.sanitizeAsJavaParameterName(argIndex)
override val kotlinType: KmTypeContainer?
get() = kotlinMetadata?.type
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
index 5d3d6e4..3e30e02 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
@@ -108,6 +108,8 @@
element = it,
)
}
+ // To be consistent with KSP consider delegates to not have a backing field.
+ .filterNot { it.kotlinMetadata?.isDelegated() == true }
}
private val allMethods = MemoizedSequence {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
index 402ab9e..7695ee9 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtils.kt
@@ -19,9 +19,9 @@
import com.squareup.javapoet.ArrayTypeName
import com.squareup.javapoet.ClassName
import com.squareup.javapoet.TypeName
+import javax.annotation.processing.ProcessingEnvironment
import javax.lang.model.element.Element
import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.NestingKind
import javax.lang.model.element.QualifiedNameable
import javax.lang.model.element.TypeElement
import javax.lang.model.element.VariableElement
@@ -45,16 +45,19 @@
*
* For reference, see the [JVM specification, section 4.3.2](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2)
*/
-internal fun VariableElement.descriptor() = "$simpleName:${asType().descriptor()}"
+internal fun VariableElement.descriptor(env: ProcessingEnvironment) =
+ "$simpleName:${asType().descriptor(env)}"
/**
* Returns the method descriptor of this [ExecutableElement].
*
* For reference, see the [JVM specification, section 4.3.3](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3)
*/
-internal fun ExecutableElement.descriptor() = "$simpleName${asType().descriptor()}"
+internal fun ExecutableElement.descriptor(env: ProcessingEnvironment) =
+ "$simpleName${asType().descriptor(env)}"
-private fun TypeMirror.descriptor() = JvmDescriptorTypeVisitor.visit(this)
+private fun TypeMirror.descriptor(env: ProcessingEnvironment) =
+ JvmDescriptorTypeVisitor.visit(this, env)
// see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2-200
internal fun String.typeNameFromJvmSignature(): TypeName {
@@ -110,13 +113,14 @@
*
* For reference, see the [JVM specification, section 4.3](http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3).
*/
-private object JvmDescriptorTypeVisitor : AbstractTypeVisitor8<String, Any?>() {
+private object JvmDescriptorTypeVisitor : AbstractTypeVisitor8<String, ProcessingEnvironment>() {
- override fun visitNoType(t: NoType, u: Any?): String = "V"
+ override fun visitNoType(t: NoType, env: ProcessingEnvironment): String = "V"
- override fun visitDeclared(t: DeclaredType, u: Any?): String = "L${t.asElement().internalName};"
+ override fun visitDeclared(t: DeclaredType, env: ProcessingEnvironment): String =
+ "L${t.asElement().internalName(env)};"
- override fun visitPrimitive(t: PrimitiveType, u: Any?): String {
+ override fun visitPrimitive(t: PrimitiveType, env: ProcessingEnvironment): String {
return when (t.kind) {
TypeKind.BYTE -> "B"
TypeKind.CHAR -> "C"
@@ -130,65 +134,46 @@
}
}
- override fun visitArray(t: ArrayType, u: Any?): String = "[" + visit(t.componentType)
+ override fun visitArray(t: ArrayType, env: ProcessingEnvironment): String =
+ "[" + visit(t.componentType, env)
- override fun visitWildcard(t: WildcardType, u: Any?): String = visitUnknown(t, u)
+ override fun visitWildcard(t: WildcardType, env: ProcessingEnvironment): String =
+ visitUnknown(t, env)
- override fun visitExecutable(t: ExecutableType, u: Any?): String {
- val parameterDescriptors = t.parameterTypes.joinToString("") { visit(it) }
- val returnDescriptor = visit(t.returnType)
+ override fun visitExecutable(t: ExecutableType, env: ProcessingEnvironment): String {
+ val parameterDescriptors = t.parameterTypes.joinToString("") { visit(it, env) }
+ val returnDescriptor = visit(t.returnType, env)
return "($parameterDescriptors)$returnDescriptor"
}
- override fun visitTypeVariable(t: TypeVariable, u: Any?): String = visit(t.upperBound)
+ override fun visitTypeVariable(t: TypeVariable, env: ProcessingEnvironment): String =
+ visit(t.upperBound, env)
- override fun visitNull(t: NullType, u: Any?): String = visitUnknown(t, u)
+ override fun visitNull(t: NullType, env: ProcessingEnvironment): String = visitUnknown(t, env)
- override fun visitError(t: ErrorType, u: Any?): String = visitDeclared(t, u)
+ override fun visitError(t: ErrorType, env: ProcessingEnvironment): String =
+ visitDeclared(t, env)
// For a type variable with multiple bounds: "the erasure of a type variable is determined
// by the first type in its bound" - JLS Sec 4.4
// See https://docs.oracle.com/javase/specs/jls/se16/html/jls-4.html#jls-4.4
- override fun visitIntersection(t: IntersectionType, u: Any?): String = visit(t.bounds[0])
+ override fun visitIntersection(t: IntersectionType, env: ProcessingEnvironment): String =
+ visit(t.bounds[0], env)
- override fun visitUnion(t: UnionType, u: Any?): String = visitUnknown(t, u)
+ override fun visitUnion(t: UnionType, env: ProcessingEnvironment): String = visitUnknown(t, env)
- override fun visitUnknown(t: TypeMirror, u: Any?): String = error("Unsupported type $t")
+ override fun visitUnknown(t: TypeMirror, env: ProcessingEnvironment): String =
+ error("Unsupported type $t")
/**
* Returns the name of this [TypeElement] in its "internal form".
*
* For reference, see the [JVM specification, section 4.2](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.2).
*/
- private val Element.internalName: String
- get() = when (this) {
- is TypeElement ->
- when (nestingKind) {
- NestingKind.TOP_LEVEL ->
- qualifiedName.toString().replace('.', '/')
- NestingKind.MEMBER, NestingKind.LOCAL ->
- enclosingElement.internalName + "$" + simpleName
- NestingKind.ANONYMOUS ->
- elementError("Unsupported nesting $nestingKind", this)
- else ->
- elementError("Unsupported, nestingKind == null", this)
- }
- is ExecutableElement -> enclosingElement.internalName
- is QualifiedNameable -> qualifiedName.toString().replace('.', '/')
- else -> simpleName.toString()
- }
-
- /**
- * Throws an exception with the error [msg] and the [element] and its enclosing elements appended.
- */
- private fun elementError(msg: String, element: Element): Nothing {
- fun buildName(element: Element): String {
- val enclosingPart =
- element.enclosingElement?.let { buildName(it) + "." } ?: ""
- val simpleName = element.simpleName.ifEmpty { "<unnamed>" }
- return enclosingPart + simpleName
- }
- val name = buildName(element)
- error("$msg - On element $name")
+ private fun Element.internalName(env: ProcessingEnvironment): String = when (this) {
+ is TypeElement -> env.elementUtils.getBinaryName(this).toString().replace('.', '/')
+ is ExecutableElement -> enclosingElement.internalName(env)
+ is QualifiedNameable -> qualifiedName.toString().replace('.', '/')
+ else -> simpleName.toString()
}
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
index 48b5336..518aac9 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
@@ -27,6 +27,7 @@
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.ExecutableElement
+import javax.lang.model.element.VariableElement
import javax.tools.Diagnostic
import kotlinx.metadata.Flag
import kotlinx.metadata.Flags
@@ -42,6 +43,7 @@
import kotlinx.metadata.KmValueParameter
import kotlinx.metadata.jvm.KotlinClassMetadata
import kotlinx.metadata.jvm.annotations
+import kotlinx.metadata.jvm.fieldSignature
import kotlinx.metadata.jvm.getterSignature
import kotlinx.metadata.jvm.setterSignature
import kotlinx.metadata.jvm.signature
@@ -58,6 +60,7 @@
}
internal class KmClassContainer(
+ private val env: JavacProcessingEnv,
private val kmClass: KmClass
) : KmFlags {
override val flags: Flags
@@ -122,7 +125,7 @@
check(method.kind == ElementKind.METHOD) {
"must pass an element type of method"
}
- return functionByDescriptor[method.descriptor()]
+ return functionByDescriptor[method.descriptor(env.delegate)]
}
private val functionByDescriptor: Map<String, KmFunctionContainer> by lazy {
@@ -142,12 +145,17 @@
check(method.kind == ElementKind.CONSTRUCTOR) {
"must pass an element type of constructor"
}
- val methodSignature = method.descriptor()
+ val methodSignature = method.descriptor(env.delegate)
return constructorList.firstOrNull { it.descriptor == methodSignature }
}
- fun getPropertyMetadata(propertyName: String): KmPropertyContainer? =
- propertyList.firstOrNull { it.name == propertyName }
+ fun getPropertyMetadata(field: VariableElement): KmPropertyContainer? {
+ check(field.kind == ElementKind.FIELD) {
+ "must pass an element type of field"
+ }
+ val fieldName = field.simpleName.toString()
+ return propertyList.firstOrNull { it.backingFieldName == fieldName || it.name == fieldName }
+ }
companion object {
/**
@@ -168,7 +176,7 @@
)
}
return when (classMetadata) {
- is KotlinClassMetadata.Class -> KmClassContainer(classMetadata.toKmClass())
+ is KotlinClassMetadata.Class -> KmClassContainer(env, classMetadata.toKmClass())
// Synthetic classes generated for various Kotlin features ($DefaultImpls,
// $WhenMappings, etc) are ignored because the data contained does not affect
// the metadata derived APIs. These classes are never referenced by user code but
@@ -274,6 +282,7 @@
internal class KmPropertyContainer(
private val kmProperty: KmProperty,
val type: KmTypeContainer,
+ val backingFieldName: String?,
val getter: KmFunctionContainer?,
val setter: KmFunctionContainer?,
val syntheticMethodForAnnotations: KmFunctionContainer?,
@@ -285,6 +294,7 @@
val typeParameters: List<KmTypeContainer>
get() = type.typeArguments
fun isNullable() = type.isNullable()
+ fun isDelegated() = Flag.Property.IS_DELEGATED(flags)
}
internal class KmTypeContainer(
@@ -422,6 +432,7 @@
KmPropertyContainer(
kmProperty = this,
type = this.returnType.asContainer(),
+ backingFieldName = fieldSignature?.name,
getter = getterSignature?.let {
KmPropertyFunctionContainerImpl(
flags = this.getterFlags,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
index 2012535..1e244b3 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
@@ -23,6 +23,7 @@
import com.google.devtools.ksp.getConstructors
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSType
+import com.google.devtools.ksp.symbol.KSValueArgument
import com.google.devtools.ksp.symbol.Origin
internal class KspAnnotation(
@@ -50,32 +51,20 @@
}
}
+ override val defaultValues: List<XAnnotationValue> by lazy {
+ wrap(ksAnnotated.defaultArguments)
+ }
+
override val annotationValues: List<XAnnotationValue> by lazy {
- // Whether the annotation value is being treated as property or abstract method depends on
- // the actual usage of the annotation. If the annotation is being used on Java source, then
- // the annotation value will have a corresponding method element, otherwise, it will become
- // a kotlin property.
- val typesByName =
- buildMap {
- typeElement.getDeclaredMethods()
- .filter {
- if ((typeElement as KspTypeElement).declaration
- .getConstructors()
- .single().parameters
- .isNotEmpty()) {
- it.isKotlinPropertyMethod()
- } else {
- it.isAbstract()
- }
- }.forEach {
- put(it.name, it.returnType)
- put(it.jvmName, it.returnType)
- }
- }
- // KSAnnotated.arguments isn't guaranteed to have the same ordering as declared in the
- // annotation declaration, so we order it manually using a map from name to index.
+ wrap(ksAnnotated.arguments)
+ }
+
+ private fun wrap(source: List<KSValueArgument>): List<XAnnotationValue> {
+ // KSAnnotated.arguments / KSAnnotated.defaultArguments isn't guaranteed to have the same
+ // ordering as declared in the annotation declaration, so we order it manually using a map
+ // from name to index.
val indexByName = typesByName.keys.mapIndexed { index, name -> name to index }.toMap()
- ksAnnotated.arguments.map {
+ return source.map {
val valueName = it.name?.asString()
?: error("Value argument $it does not have a name.")
val valueType = typesByName[valueName]
@@ -84,6 +73,31 @@
}.sortedBy { indexByName[it.name] }
}
+ // A map of annotation value name to type.
+ private val typesByName: Map<String, XType> by lazy {
+ buildMap {
+ typeElement.getDeclaredMethods()
+ .filter {
+ // Whether the annotation value is being treated as property or
+ // abstract method depends on the actual usage of the annotation.
+ // If the annotation is being used on Java source, then the annotation
+ // value will have a corresponding method element, otherwise, it
+ // will become a kotlin property.
+ if ((typeElement as KspTypeElement).declaration
+ .getConstructors()
+ .single().parameters
+ .isNotEmpty()) {
+ it.isKotlinPropertyMethod()
+ } else {
+ it.isAbstract()
+ }
+ }.forEach {
+ put(it.name, it.returnType)
+ put(it.jvmName, it.returnType)
+ }
+ }
+ }
+
override fun <T : Annotation> asAnnotationBox(annotationClass: Class<T>): XAnnotationBox<T> {
return KspAnnotationBox(
env = env,
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 354ee85..44bb15d 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -174,7 +174,7 @@
private val _declaredFields by lazy {
_declaredProperties.filter {
- it.declaration.hasBackingFieldFixed
+ it.declaration.hasBackingField
}
}
@@ -410,13 +410,6 @@
}
}
- /**
- * Workaround for https://github.com/google/ksp/issues/529 where KSP returns false for
- * backing field when the property has a lateinit modifier.
- */
- private val KSPropertyDeclaration.hasBackingFieldFixed
- get() = hasBackingField || modifiers.contains(Modifier.LATEINIT)
-
@OptIn(KspExperimental::class)
fun KSDeclarationContainer?.getDeclarationsInSourceOrder() = this?.let {
env.resolver.getDeclarationsInSourceOrder(it)
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
index 2953253..71d5c12 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
@@ -708,6 +708,20 @@
}.forEach { typeElement ->
val annotation = typeElement.requireAnnotation<JavaAnnotationWithDefaults>()
+ assertThat(annotation.defaultValues.map { it.name })
+ .containsExactly(
+ "stringVal",
+ "stringArrayVal",
+ "typeVal",
+ "typeArrayVal",
+ "intVal",
+ "intArrayVal",
+ "enumVal",
+ "enumArrayVal",
+ "otherAnnotationVal",
+ "otherAnnotationArrayVal"
+ ).inOrder()
+
assertThat(annotation.get<Int>("intVal"))
.isEqualTo(3)
assertThat(annotation.get<List<Int>>("intArrayVal"))
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
index 866159c..c64b056 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
@@ -1070,28 +1070,18 @@
val annotation = getAnnotation(invocation)
// Compare the AnnotationSpec string ignoring whitespace
- if (sourceKind == SourceKind.KOTLIN && !invocation.isKsp && isTypeAnnotation) {
- assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
- .isEqualTo("""
- @test.MyAnnotation(
- stringParam = "1",
- stringArrayParam = {"3", "5", "7"},
- stringVarArgsParam = {"9", "11", "13"}
- )
- """.removeWhiteSpace())
- } else {
- assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
- .isEqualTo("""
- @test.MyAnnotation(
- stringParam = "1",
- stringParam2 = "2",
- stringArrayParam = {"3", "5", "7"},
- stringVarArgsParam = {"9", "11", "13"}
- )
- """.removeWhiteSpace())
- val stringParam2 = annotation.getAnnotationValue("stringParam2")
- checkSingleValue(stringParam2, "2")
- }
+ assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
+ .isEqualTo("""
+ @test.MyAnnotation(
+ stringParam = "1",
+ stringParam2 = "2",
+ stringArrayParam = {"3", "5", "7"},
+ stringVarArgsParam = {"9", "11", "13"}
+ )
+ """.removeWhiteSpace())
+ val stringParam2 = annotation.getAnnotationValue("stringParam2")
+ checkSingleValue(stringParam2, "2")
+
val stringParam = annotation.getAnnotationValue("stringParam")
checkSingleValue(stringParam, "1")
@@ -1378,7 +1368,8 @@
String[] stringArrayParam() default {"3", "5", "7"};
}
interface MyInterface {}
- @MyAnnotation(stringParam = "1") class MyClass implements @MyAnnotation MyInterface {}
+ @MyAnnotation(stringParam = "2") class MyClass implements
+ @MyAnnotation(stringParam = "2") MyInterface {}
""".trimIndent()
) as Source.JavaSource,
kotlinSource = Source.kotlin(
@@ -1392,7 +1383,8 @@
val stringArrayParam: Array<String> = ["3", "5", "7"]
)
interface MyInterface
- @MyAnnotation(stringParam = "1") class MyClass : @MyAnnotation MyInterface
+ @MyAnnotation(stringParam = "2") class MyClass :
+ @MyAnnotation(stringParam = "2") MyInterface
""".trimIndent()
) as Source.KotlinSource
) { invocation ->
@@ -1400,52 +1392,32 @@
if (sourceKind == SourceKind.JAVA && invocation.isKsp && !isPreCompiled) {
// TODO(https://github.com/google/ksp/issues/1392) Remove the condition
// when bugs are fixed in ksp/kapt.
- assertThat(annotation.getAnnotationValue("stringParam").value).isEqualTo("1")
+ assertThat(annotation.getAnnotationValue("stringParam").value)
+ .isEqualTo("2")
assertThat(annotation.getAnnotationValue("stringParam2").value).isEqualTo("1")
assertThat(
annotation.getAnnotationValue("stringArrayParam")
.asAnnotationValueList().firstOrNull()?.value).isNull()
- } else if (sourceKind == SourceKind.KOTLIN && !invocation.isKsp && isTypeAnnotation) {
- // TODO(b/285040492) Remove the condition when bugs are fixed in ksp/kapt.
- assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
- .isEqualTo("""
- @test.MyAnnotation
- """.removeWhiteSpace())
-
- assertThat(
- annotation.toAnnotationSpec(
- includeDefaultValues = false).toString().removeWhiteSpace())
- .isEqualTo("""
- @test.MyAnnotation
- """.removeWhiteSpace())
} else {
// Compare the AnnotationSpec string ignoring whitespace
assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
.isEqualTo("""
@test.MyAnnotation(
- stringParam = "1",
+ stringParam = "2",
stringParam2 = "1",
stringArrayParam = {"3", "5", "7"}
)
""".removeWhiteSpace())
- if (!isTypeAnnotation) {
- assertThat(
- annotation.toAnnotationSpec(
- includeDefaultValues = false).toString().removeWhiteSpace())
- .isEqualTo("""
- @test.MyAnnotation(
- stringParam = "1"
- )
- """.removeWhiteSpace())
- } else {
- assertThat(
- annotation.toAnnotationSpec(
- includeDefaultValues = false).toString().removeWhiteSpace())
- .isEqualTo("""
- @test.MyAnnotation
- """.removeWhiteSpace())
- }
- if (!invocation.isKsp) {
+ assertThat(
+ annotation.toAnnotationSpec(
+ includeDefaultValues = false).toString().removeWhiteSpace())
+ .isEqualTo("""
+ @test.MyAnnotation(
+ stringParam = "2"
+ )
+ """.removeWhiteSpace())
+
+ if (!invocation.isKsp && !isTypeAnnotation) {
// Check that "XAnnotation#toAnnotationSpec()" matches JavaPoet's
// "AnnotationSpec.get(AnnotationMirror)"
assertThat(annotation.toAnnotationSpec(includeDefaultValues = false))
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
index db2aa22..181265e6 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XExecutableElementTest.kt
@@ -1429,4 +1429,52 @@
)
}
}
+
+ @Test
+ fun receiverParameterNames(@TestParameter isPrecompiled: Boolean) {
+ val kotlinSource = Source.kotlin(
+ "foo.bar.Subject.kt",
+ """
+ package foo.bar
+ abstract class Subject {
+ fun Bar.method(): Unit = TODO()
+ fun Bar.methodWithParam(name: String): Unit = TODO()
+ abstract fun Bar.abstractMethod()
+ abstract fun Bar.abstractMethodWithParam(name: String)
+ @JvmName("newMethodWithJvmName")
+ fun Bar.methodWithJvmName(): Unit = TODO()
+ @JvmName("newMethodWithJvmNameAndParam")
+ fun Bar.methodWithJvmNameAndParam(name: String): Unit = TODO()
+ }
+ class Bar
+ """.trimIndent())
+ runProcessorTest(
+ sources = if (isPrecompiled) {
+ emptyList()
+ } else {
+ listOf(kotlinSource)
+ },
+ classpath = if (isPrecompiled) {
+ compileFiles(listOf(kotlinSource))
+ } else {
+ emptyList()
+ }
+ ) { invocation ->
+ val subject = invocation.processingEnv.requireTypeElement("foo.bar.Subject")
+
+ // Assert on the method and parameter names of each declared method.
+ assertThat(
+ subject.getDeclaredMethods().map { method ->
+ "${method.name}(${method.parameters.joinToString(", ") { it.name }})"
+ }
+ ).containsExactly(
+ "method(\$this\$method)",
+ "methodWithParam(\$this\$methodWithParam, name)",
+ "abstractMethod(\$this\$abstractMethod)",
+ "abstractMethodWithParam(\$this\$abstractMethodWithParam, name)",
+ "methodWithJvmName(\$this\$methodWithJvmName)",
+ "methodWithJvmNameAndParam(\$this\$methodWithJvmNameAndParam, name)",
+ ).inOrder()
+ }
+ }
}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index 0d3d952..5b165ae 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -29,6 +29,7 @@
import androidx.room.compiler.processing.util.compileFiles
import androidx.room.compiler.processing.util.getAllFieldNames
import androidx.room.compiler.processing.util.getDeclaredField
+import androidx.room.compiler.processing.util.getDeclaredMethodByJvmName
import androidx.room.compiler.processing.util.getField
import androidx.room.compiler.processing.util.getMethodByJvmName
import androidx.room.compiler.processing.util.runProcessorTest
@@ -822,6 +823,26 @@
}
@Test
+ fun lazyProperty() {
+ val src = Source.kotlin(
+ "Subject.kt",
+ """
+ class Subject {
+ val myLazy by lazy { "wow" }
+ }
+ """.trimIndent()
+ )
+ runTest(sources = listOf(src)) {
+ val subject = it.processingEnv.requireTypeElement("Subject")
+ val fields = subject.getDeclaredFields()
+ assertThat(fields).isEmpty()
+ val method = subject.getDeclaredMethodByJvmName("getMyLazy")
+ assertThat(method).isNotNull()
+ assertThat(method.isKotlinPropertyMethod()).isTrue()
+ }
+ }
+
+ @Test
fun declaredAndInstanceMethods() {
val src = Source.kotlin(
"Foo.kt",
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
index 86d3822..90f1bac 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/JvmDescriptorUtilsTest.kt
@@ -425,9 +425,9 @@
roundEnv.getElementsAnnotatedWith(annotations.first()).map { element ->
when (element.kind) {
FIELD ->
- MoreElements.asVariable(element).descriptor()
+ MoreElements.asVariable(element).descriptor(processingEnv)
METHOD, CONSTRUCTOR ->
- MoreElements.asExecutable(element).descriptor()
+ MoreElements.asExecutable(element).descriptor(processingEnv)
else -> error("Unsupported element to describe.")
}
}.toSet().let(handler)
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
index 62cb00e..0e97e4a 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/javac/kotlin/KotlinMetadataElementTest.kt
@@ -19,7 +19,6 @@
import androidx.kruth.assertThat
import androidx.kruth.assertWithMessage
import androidx.room.compiler.processing.XNullability
-import androidx.room.compiler.processing.XProcessingEnvConfig
import androidx.room.compiler.processing.javac.JavacProcessingEnv
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.XTestInvocation
@@ -27,7 +26,6 @@
import androidx.room.compiler.processing.util.runJavaProcessorTest
import androidx.room.compiler.processing.util.runKaptTest
import androidx.room.compiler.processing.util.sanitizeAsJavaParameterName
-import javax.annotation.processing.ProcessingEnvironment
import javax.lang.model.element.ExecutableElement
import javax.lang.model.element.TypeElement
import javax.lang.model.util.ElementFilter
@@ -55,9 +53,9 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { processingEnv ->
+ simpleRun(listOf(src)) { env ->
val (testClassElement, metadataElement) = getMetadataElement(
- processingEnv,
+ env,
"Subject"
)
val constructors = testClassElement.getConstructors()
@@ -109,9 +107,9 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { processingEnv ->
+ simpleRun(listOf(src)) { env ->
val (testClassElement, metadataElement) = getMetadataElement(
- processingEnv,
+ env,
"Subject"
)
testClassElement.getDeclaredMethod("functionWithParams")
@@ -157,14 +155,14 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
+ simpleRun(listOf(src)) { env ->
val (testClassElement, metadataElement) = getMetadataElement(
- invocation,
+ env,
"Subject"
)
assertThat(
testClassElement.getConstructors().map {
- val desc = it.descriptor()
+ val desc = it.descriptor(env.delegate)
desc to (desc == metadataElement.primaryConstructorSignature)
}
).containsExactly(
@@ -191,14 +189,15 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
+ simpleRun(listOf(src)) { env ->
val (testClassElement, metadataElement) = getMetadataElement(
- invocation,
+ env,
"Subject"
)
assertThat(
testClassElement.getDeclaredMethods().map {
- it.simpleName.toString() to metadataElement.getFunctionMetadata(it)?.isSuspend()
+ it.simpleName.toString() to metadataElement.getFunctionMetadata(it)
+ ?.isSuspend()
}
).containsExactly(
"emptyFunction" to false,
@@ -220,12 +219,12 @@
object AnObject
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
- val (_, objectTypeMetadata) = getMetadataElement(invocation, "AnObject")
+ simpleRun(listOf(src)) { env ->
+ val (_, objectTypeMetadata) = getMetadataElement(env, "AnObject")
assertThat(objectTypeMetadata.isObject()).isTrue()
- val (_, classTypeMetadata) = getMetadataElement(invocation, "KotlinClass")
+ val (_, classTypeMetadata) = getMetadataElement(env, "KotlinClass")
assertThat(classTypeMetadata.isObject()).isFalse()
- val (_, interfaceMetadata) = getMetadataElement(invocation, "KotlinInterface")
+ val (_, interfaceMetadata) = getMetadataElement(env, "KotlinInterface")
assertThat(interfaceMetadata.isObject()).isFalse()
}
}
@@ -241,9 +240,9 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
+ simpleRun(listOf(src)) { env ->
val (testDaoElement, testDaoMetadata) = getMetadataElement(
- invocation,
+ env,
"Subject"
)
val nonNullListMethod = testDaoElement.getDeclaredMethod("nonNullList")
@@ -273,38 +272,48 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
- val (_, testMetadata) = getMetadataElement(
- invocation,
+ simpleRun(listOf(src)) { env ->
+ val (typeElement, testMetadata) = getMetadataElement(
+ env,
"Properties"
)
- testMetadata.getPropertyMetadata("nonNull").let { property ->
+ testMetadata.getPropertyMetadata(
+ typeElement.getDeclaredField("nonNull")
+ ).let { property ->
assertThat(property?.name).isEqualTo("nonNull")
assertThat(property?.typeParameters).isEmpty()
assertThat(property?.isNullable()).isFalse()
}
- testMetadata.getPropertyMetadata("nullable").let { property ->
+ testMetadata.getPropertyMetadata(
+ typeElement.getDeclaredField("nullable")
+ ).let { property ->
assertThat(property?.name).isEqualTo("nullable")
assertThat(property?.typeParameters).isEmpty()
assertThat(property?.isNullable()).isTrue()
}
- testMetadata.getPropertyMetadata("nullableTypeArgument").let { property ->
+ testMetadata.getPropertyMetadata(
+ typeElement.getDeclaredField("nullableTypeArgument")
+ ).let { property ->
assertThat(property?.name).isEqualTo("nullableTypeArgument")
assertThat(property?.isNullable()).isFalse()
assertThat(property?.typeParameters).hasSize(1)
assertThat(property?.typeParameters?.single()?.isNullable()).isTrue()
}
- testMetadata.getPropertyMetadata("nonNullTypeArgument").let { property ->
+ testMetadata.getPropertyMetadata(
+ typeElement.getDeclaredField("nonNullTypeArgument")
+ ).let { property ->
assertThat(property?.name).isEqualTo("nonNullTypeArgument")
assertThat(property?.isNullable()).isFalse()
assertThat(property?.typeParameters).hasSize(1)
assertThat(property?.typeParameters?.single()?.isNullable()).isFalse()
}
- testMetadata.getPropertyMetadata("multipleTypeArguments").let { property ->
+ testMetadata.getPropertyMetadata(
+ typeElement.getDeclaredField("multipleTypeArguments")
+ ).let { property ->
assertThat(property?.name).isEqualTo("multipleTypeArguments")
assertThat(property?.isNullable()).isFalse()
assertThat(property?.typeParameters).hasSize(2)
@@ -341,9 +350,9 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
+ simpleRun(listOf(src)) { env ->
val (element, metadata) = getMetadataElement(
- invocation,
+ env,
"Subject"
)
@@ -485,7 +494,9 @@
// tests value class properties. They won't show up in KAPT stubs since they don't have
// valid java source names but we still validate them here for consistency. Maybe one
// day we'll change Javac element to include these if we support Kotlin codegen in KAPT
- metadata.getPropertyMetadata("valueProp").let { valueProp ->
+ metadata.getPropertyMetadata(
+ element.getDeclaredField("valueProp")
+ ).let { valueProp ->
assertGetter(
kmFunction = valueProp?.getter,
name = "getValueProp",
@@ -499,7 +510,9 @@
paramNullable = true
)
}
- metadata.getPropertyMetadata("internalValueProp").let { valueProp ->
+ metadata.getPropertyMetadata(
+ element.getDeclaredField("internalValueProp")
+ ).let { valueProp ->
assertGetter(
kmFunction = valueProp?.getter,
name = "getInternalValueProp",
@@ -529,9 +542,9 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
+ simpleRun(listOf(src)) { env ->
val (element, metadata) = getMetadataElement(
- invocation,
+ env,
"Subject"
)
metadata.getFunctionMetadata(
@@ -578,9 +591,9 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
+ simpleRun(listOf(src)) { env ->
val (testDaoElement, testDaoMetadata) = getMetadataElement(
- invocation,
+ env,
"Subject"
)
fun assertParams(params: List<KmValueParameterContainer>?) {
@@ -617,17 +630,17 @@
val src = Source.kotlin(
"Subject.kt",
"""
- interface Subject {
- val nullableArrayWithNonNullComponent : Array<Int>?
- val nullableArrayWithNullableComponent : Array<Int?>?
- val nonNullArrayWithNonNullComponent : Array<Int>
- val nonNullArrayWithNullableComponent : Array<Int?>
+ class Subject {
+ val nullableArrayWithNonNullComponent : Array<Int>? = TODO()
+ val nullableArrayWithNullableComponent : Array<Int?>? = TODO()
+ val nonNullArrayWithNonNullComponent : Array<Int> = TODO()
+ val nonNullArrayWithNullableComponent : Array<Int?> = TODO()
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
- val (_, metadata) = getMetadataElement(
- invocation,
+ simpleRun(listOf(src)) { env ->
+ val (typeElement, metadata) = getMetadataElement(
+ env,
"Subject"
)
val propertyNames = listOf(
@@ -638,7 +651,7 @@
)
assertThat(
propertyNames
- .mapNotNull(metadata::getPropertyMetadata)
+ .mapNotNull { metadata.getPropertyMetadata(typeElement.getDeclaredField(it)) }
.map {
Triple(it.name, it.isNullable(), it.typeParameters.single().isNullable())
}
@@ -669,18 +682,18 @@
abstract class WithSuperType : Map<String, Int?> {}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
- val (_, simple) = getMetadataElement(invocation, "Simple")
+ simpleRun(listOf(src)) { env ->
+ val (_, simple) = getMetadataElement(env, "Simple")
assertThat(simple.type.isNullable()).isFalse()
assertThat(simple.type.typeArguments).isEmpty()
- val (_, twoArgGeneric) = getMetadataElement(invocation, "TwoArgGeneric")
+ val (_, twoArgGeneric) = getMetadataElement(env, "TwoArgGeneric")
assertThat(twoArgGeneric.type.isNullable()).isFalse()
assertThat(twoArgGeneric.type.typeArguments).hasSize(2)
assertThat(twoArgGeneric.type.typeArguments[0].isNullable()).isFalse()
assertThat(twoArgGeneric.type.typeArguments[1].isNullable()).isFalse()
- val (_, withUpperBounds) = getMetadataElement(invocation, "WithUpperBounds")
+ val (_, withUpperBounds) = getMetadataElement(env, "WithUpperBounds")
assertThat(withUpperBounds.type.typeArguments).hasSize(2)
assertThat(withUpperBounds.type.typeArguments[0].upperBounds).hasSize(1)
assertThat(withUpperBounds.type.typeArguments[0].upperBounds[0].isNullable())
@@ -689,7 +702,7 @@
assertThat(withUpperBounds.type.typeArguments[1].upperBounds[0].isNullable())
.isTrue()
- val (_, withSuperType) = getMetadataElement(invocation, "WithSuperType")
+ val (_, withSuperType) = getMetadataElement(env, "WithSuperType")
assertThat(withSuperType.superType?.typeArguments?.get(0)?.isNullable()).isFalse()
assertThat(withSuperType.superType?.typeArguments?.get(1)?.isNullable()).isTrue()
}
@@ -707,17 +720,23 @@
}
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
- val (_, subject) = getMetadataElement(invocation, "Subject")
- subject.getPropertyMetadata("simple")!!.type.erasure().let {
+ simpleRun(listOf(src)) { env ->
+ val (typeElement, subject) = getMetadataElement(env, "Subject")
+ subject.getPropertyMetadata(
+ typeElement.getDeclaredField("simple")
+ )!!.type.erasure().let {
assertThat(it.isNullable()).isFalse()
assertThat(it.typeArguments).isEmpty()
}
- subject.getPropertyMetadata("nullableGeneric")!!.type.erasure().let {
+ subject.getPropertyMetadata(
+ typeElement.getDeclaredField("nullableGeneric")
+ )!!.type.erasure().let {
assertThat(it.isNullable()).isTrue()
assertThat(it.typeArguments).isEmpty()
}
- subject.getPropertyMetadata("nonNullGeneric")!!.type.erasure().let {
+ subject.getPropertyMetadata(
+ typeElement.getDeclaredField("nonNullGeneric")
+ )!!.type.erasure().let {
assertThat(it.isNullable()).isFalse()
assertThat(it.typeArguments).isEmpty()
}
@@ -749,7 +768,7 @@
) { invocation ->
val (_, metadata) =
getMetadataElement(
- (invocation.processingEnv as JavacProcessingEnv).delegate,
+ invocation.processingEnv as JavacProcessingEnv,
"KotlinClass"
)
assertThat(metadata).isNotNull()
@@ -779,8 +798,8 @@
abstract class C
""".trimIndent()
)
- simpleRun(listOf(src)) { invocation ->
- val (subjectElement, subjectMetadata) = getMetadataElement(invocation, "Subject")
+ simpleRun(listOf(src)) { env ->
+ val (subjectElement, subjectMetadata) = getMetadataElement(env, "Subject")
fun assertKmFunctionFound(functionName: String) {
val kmFunction = subjectMetadata.getFunctionMetadata(
subjectElement.getDeclaredMethod(functionName)
@@ -794,6 +813,59 @@
}
@Test
+ fun properties_anonymousNestingKind() {
+ // Only private functions are relevant to the test since public (or internal) properties
+ // are required to declare their type explicitly when right-hand side is ambiguous.
+ // b/232742201
+ val src = Source.kotlin(
+ "Subject.kt",
+ """
+ class Subject {
+ private val lazyA by lazy {
+ object: A { }
+ }
+ private val lazyAB by lazy {
+ object: A, B { }
+ }
+ private val lazyABC by lazy {
+ object: C(), A, B { }
+ }
+ private val lazyC by lazy {
+ object: C() { }
+ }
+ private val lazyAC by lazy {
+ object: C(), A { }
+ }
+ private val lazyAB_declaredA: A by lazy {
+ object: A, B { }
+ }
+ private val lazyAB_declaredB: B by lazy {
+ object: A, B { }
+ }
+ private val lazyABC_declaredC: C by lazy {
+ object: C(), A { }
+ }
+ }
+
+ interface A
+ interface B
+ abstract class C
+ """.trimIndent()
+ )
+ simpleRun(
+ sources = listOf(src)
+ ) { env ->
+ val subject = env.requireTypeElement("Subject")
+ subject.getDeclaredFields().forEach {
+ assertThat(it.getter).isNotNull()
+ }
+ subject.getDeclaredMethods().forEach {
+ assertThat(it.isKotlinPropertyMethod()).isTrue()
+ }
+ }
+ }
+
+ @Test
fun ignore_syntheticMetadata_defaultImpls() {
val src = Source.kotlin(
"Subject.kt",
@@ -806,8 +878,8 @@
simpleRun(
sources = listOf(src),
kotlincArgs = listOf("-Xjvm-default=disable")
- ) {
- val subjectElement = processingEnv.requireTypeElement("Subject.DefaultImpls")
+ ) { env ->
+ val subjectElement = env.requireTypeElement("Subject.DefaultImpls")
// Call metadata derived API causing it to be read
assertThat(subjectElement.isKotlinObject()).isFalse()
assertCompilationResult {
@@ -840,9 +912,9 @@
)
simpleRun(
sources = listOf(src),
- ) {
- assertThat(processingEnv.findTypeElement("Subject.Fruit")).isNotNull()
- val subjectElement = processingEnv.findTypeElement("Subject.WhenMappings")
+ ) { env ->
+ assertThat(env.findTypeElement("Subject.Fruit")).isNotNull()
+ val subjectElement = env.findTypeElement("Subject.WhenMappings")
// Currently $WhenMapping has the ACC_SYNTHETIC flag making it unreadable by
// annotation processors making it impossible to verify synthetic metadata is
// ignored.
@@ -877,19 +949,19 @@
)
simpleRun(
sources = listOf(aSrc, bSrc),
- ) {
+ ) { env ->
// Find the multi file class facade element
- val facadeElement = processingEnv.requireTypeElement("Subject")
+ val facadeElement = env.requireTypeElement("Subject")
// Call metadata derived API causing it to be read
assertThat(facadeElement.isKotlinObject()).isFalse()
// Try to find the multi file class part elements, currently these classes have the
// ACC_SYNTHETIC flag making them unreadable by annotation processors and impossible to
// verify that multi file metadata is ignored.
- val facadePartOne = processingEnv.findTypeElement("Subject__AKt")
+ val facadePartOne = env.findTypeElement("Subject__AKt")
?: throw AssumptionViolatedException("No test if MultiFileClassPart is not found")
assertThat(facadePartOne.isKotlinObject()).isFalse()
- val facadePartTwo = processingEnv.findTypeElement("Subject__BKt")
+ val facadePartTwo = env.findTypeElement("Subject__BKt")
?: throw AssumptionViolatedException("No test if MultiFileClassPart is not found")
assertThat(facadePartTwo.isKotlinObject()).isFalse()
assertCompilationResult {
@@ -904,13 +976,16 @@
it.simpleName.toString() == name
}
+ private fun TypeElement.getDeclaredField(name: String) =
+ ElementFilter.fieldsIn(enclosedElements).first { it.simpleName.toString() == name }
+
private fun TypeElement.getConstructors() = ElementFilter.constructorsIn(enclosedElements)
@Suppress("NAME_SHADOWING") // intentional
private fun simpleRun(
sources: List<Source> = emptyList(),
kotlincArgs: List<String> = emptyList(),
- handler: XTestInvocation.(ProcessingEnvironment) -> Unit
+ handler: XTestInvocation.(JavacProcessingEnv) -> Unit
) {
val (sources, classpath) = if (preCompiled) {
emptyList<Source>() to compileFiles(sources)
@@ -922,18 +997,17 @@
classpath = classpath,
kotlincArguments = kotlincArgs
) {
- val processingEnv = it.processingEnv
- if (processingEnv !is JavacProcessingEnv) {
+ val env = it.processingEnv
+ if (env !is JavacProcessingEnv) {
throw AssumptionViolatedException("This test only works for java/kapt compilation")
}
- it.handler(processingEnv.delegate)
+ it.handler(env)
}
}
- private fun getMetadataElement(processingEnv: ProcessingEnvironment, qName: String) =
- processingEnv.elementUtils.getTypeElement(qName).let {
- it to KmClassContainer.createFor(
- JavacProcessingEnv(processingEnv, XProcessingEnvConfig.DEFAULT), it)!!
+ private fun getMetadataElement(env: JavacProcessingEnv, qName: String) =
+ env.elementUtils.getTypeElement(qName).let {
+ it to KmClassContainer.createFor(env, it)!!
}
companion object {
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 86990ae..425bf1c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -64,6 +64,8 @@
val CANNOT_USE_UNBOUND_GENERICS_IN_DAO_CLASSES = "Cannot use unbound generics in Dao classes." +
" If you are trying to create a base DAO, create a normal class, extend it with type" +
" params then mark the subclass with @Dao."
+ val CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY = "Cannot use @MapColumn and " +
+ " @MapInfo annotation in the same function. Please prefer using @MapColumn only."
val CANNOT_FIND_GETTER_FOR_FIELD = "Cannot find getter for field."
val CANNOT_FIND_SETTER_FOR_FIELD = "Cannot find setter for field."
val MISSING_PRIMARY_KEY = "An entity must have at least 1 field annotated with @PrimaryKey"
@@ -152,24 +154,18 @@
val DELETION_MISSING_PARAMS = "Method annotated with" +
" @Delete but does not have any parameters to delete."
- fun cannotMapInfoSpecifiedColumn(column: String, columnsInQuery: List<String>) =
- "Column specified in the provided @MapInfo annotation must be present in the query. " +
+ fun cannotMapSpecifiedColumn(column: String, columnsInQuery: List<String>, annotation: String) =
+ "Column specified in the provided @$annotation annotation must be present in the query. " +
"Provided: $column. Columns found: ${columnsInQuery.joinToString(", ")}"
val MAP_INFO_MUST_HAVE_AT_LEAST_ONE_COLUMN_PROVIDED = "To use the @MapInfo annotation, you " +
"must provide either the key column name, value column name, or both."
- fun keyMayNeedMapInfo(keyArg: String): String {
+ fun mayNeedMapColumn(columnArg: String): String {
return """
- Looks like you may need to use @MapInfo to clarify the 'keyColumn' needed for
- the return type of a method. Type argument that needs @MapInfo: $keyArg
- """.trim()
- }
-
- fun valueMayNeedMapInfo(valueArg: String): String {
- return """
- Looks like you may need to use @MapInfo to clarify the 'valueColumn' needed for
- the return type of a method. Type argument that needs @MapInfo: $valueArg
+ Looks like you may need to use @MapColumn to clarify the 'columnName' needed for
+ type argument(s) in the return type of a method. Type argument that needs
+ @MapColumn: $columnArg
""".trim()
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
index d9333f1..50be0d2 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/QueryMethodProcessor.kt
@@ -26,7 +26,7 @@
import androidx.room.parser.ParsedQuery
import androidx.room.parser.QueryType
import androidx.room.parser.SqlParser
-import androidx.room.processor.ProcessorErrors.cannotMapInfoSpecifiedColumn
+import androidx.room.processor.ProcessorErrors.cannotMapSpecifiedColumn
import androidx.room.solver.TypeAdapterExtras
import androidx.room.solver.query.result.PojoRowAdapter
import androidx.room.verifier.ColumnInfo
@@ -208,6 +208,7 @@
)
}
+ @Suppress("DEPRECATION") // Due to MapInfo usage
private fun getQueryMethod(
delegate: MethodProcessorDelegate,
returnType: XType,
@@ -284,6 +285,7 @@
* Parse @MapInfo annotation, validate its inputs and put information in the bag of extras,
* it will be later used by the TypeAdapterStore.
*/
+ @Suppress("DEPRECATION") // Due to @MapInfo usage
private fun processMapInfo(
mapInfoAnnotation: XAnnotationBox<androidx.room.MapInfo>,
query: ParsedQuery,
@@ -323,18 +325,20 @@
keyColumn.isEmpty() || resultColumns.contains(keyColumn, keyTable),
queryExecutableElement
) {
- cannotMapInfoSpecifiedColumn(
+ cannotMapSpecifiedColumn(
(if (keyTable != null) "$keyTable." else "") + keyColumn,
- resultColumns.map { it.name }
+ resultColumns.map { it.name },
+ androidx.room.MapInfo::class.java.simpleName
)
}
context.checker.check(
valueColumn.isEmpty() || resultColumns.contains(valueColumn, valueTable),
queryExecutableElement
) {
- cannotMapInfoSpecifiedColumn(
+ cannotMapSpecifiedColumn(
(if (valueTable != null) "$valueTable." else "") + valueColumn,
- resultColumns.map { it.name }
+ resultColumns.map { it.name },
+ androidx.room.MapInfo::class.java.simpleName
)
}
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
index f51988f..f2ec672 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/processor/RawQueryMethodProcessor.kt
@@ -60,10 +60,10 @@
val query = SqlParser.rawQueryForTables(observedTableNames)
// build the query but don't calculate result info since we just guessed it.
val resultBinder = delegate.findResultBinder(returnType, query) {
+ @Suppress("DEPRECATION")
delegate.executableElement.getAnnotation(androidx.room.MapInfo::class)?.let {
- val keyColumn = it.value.keyColumn.toString()
- val valueColumn = it.value.valueColumn.toString()
-
+ val keyColumn = it.value.keyColumn
+ val valueColumn = it.value.valueColumn
context.checker.check(
keyColumn.isNotEmpty() || valueColumn.isNotEmpty(),
executableElement,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
index d6e4dcb..614b818 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/TypeAdapterStore.kt
@@ -77,6 +77,7 @@
import androidx.room.solver.query.result.MapQueryResultAdapter
import androidx.room.solver.query.result.MapValueResultAdapter
import androidx.room.solver.query.result.MultimapQueryResultAdapter
+import androidx.room.solver.query.result.MultimapQueryResultAdapter.Companion.getMapColumnName
import androidx.room.solver.query.result.MultimapQueryResultAdapter.Companion.validateMapKeyTypeArg
import androidx.room.solver.query.result.MultimapQueryResultAdapter.Companion.validateMapValueTypeArg
import androidx.room.solver.query.result.MultimapQueryResultAdapter.MapType.Companion.isSparseArray
@@ -624,29 +625,40 @@
// Get @MapInfo info if any (this might be null)
val mapInfo = extras.getData(MapInfo::class)
+ val mapKeyColumn = getMapColumnName(context, query, keyTypeArg)
+ val mapValueColumn = getMapColumnName(context, query, valueTypeArg)
+ if (mapInfo != null && (mapKeyColumn != null || mapValueColumn != null)) {
+ context.logger.e(
+ ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+ )
+ }
+
+ val mappedKeyColumnName = mapKeyColumn ?: mapInfo?.keyColumnName
+ val mappedValueColumnName = mapValueColumn ?: mapInfo?.valueColumnName
+
val keyRowAdapter = findRowAdapter(
typeMirror = keyTypeArg,
query = query,
- columnName = mapInfo?.keyColumnName
+ columnName = mappedKeyColumnName
) ?: return null
val valueRowAdapter = findRowAdapter(
typeMirror = valueTypeArg,
query = query,
- columnName = mapInfo?.valueColumnName
+ columnName = mappedValueColumnName
) ?: return null
validateMapKeyTypeArg(
context = context,
keyTypeArg = keyTypeArg,
keyReader = findCursorValueReader(keyTypeArg, null),
- mapInfo = mapInfo
+ keyColumnName = mappedKeyColumnName
)
validateMapValueTypeArg(
context = context,
valueTypeArg = valueTypeArg,
valueReader = findCursorValueReader(valueTypeArg, null),
- mapInfo = mapInfo
+ valueColumnName = mappedValueColumnName
)
return GuavaImmutableMultimapQueryResultAdapter(
context = context,
@@ -694,18 +706,25 @@
// Get @MapInfo info if any (this might be null)
val mapInfo = extras.getData(MapInfo::class)
+ val mapColumn = getMapColumnName(context, query, keyTypeArg)
+ if (mapInfo != null && mapColumn != null) {
+ context.logger.e(
+ ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+ )
+ }
+ val mappedKeyColumnName = mapColumn ?: mapInfo?.keyColumnName
val keyRowAdapter = findRowAdapter(
typeMirror = keyTypeArg,
query = query,
- columnName = mapInfo?.keyColumnName
+ columnName = mappedKeyColumnName
) ?: return null
validateMapKeyTypeArg(
context = context,
keyTypeArg = keyTypeArg,
keyReader = findCursorValueReader(keyTypeArg, null),
- mapInfo = mapInfo
+ keyColumnName = mappedKeyColumnName
)
val mapValueResultAdapter = findMapValueResultAdapter(
@@ -801,17 +820,25 @@
}
val valueTypeArg = mapValueTypeArg.typeArguments.single().extendsBoundOrSelf()
+ val mapColumnName = getMapColumnName(context, query, valueTypeArg)
+ if (mapColumnName != null && mapInfo != null) {
+ context.logger.e(
+ ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+ )
+ }
+
+ val mappedValueColumnName = mapColumnName ?: mapInfo?.valueColumnName
val valueRowAdapter = findRowAdapter(
typeMirror = valueTypeArg,
query = query,
- columnName = mapInfo?.valueColumnName
+ columnName = mappedValueColumnName
) ?: return null
validateMapValueTypeArg(
context = context,
valueTypeArg = valueTypeArg,
valueReader = findCursorValueReader(valueTypeArg, null),
- mapInfo = mapInfo
+ valueColumnName = mappedValueColumnName
)
return MapValueResultAdapter.EndMapValueResultAdapter(
@@ -821,14 +848,19 @@
)
} else if (mapValueTypeArg.isTypeOf(java.util.Map::class)) {
val keyTypeArg = mapValueTypeArg.typeArguments[0].extendsBoundOrSelf()
+ val valueTypeArg = mapValueTypeArg.typeArguments[1].extendsBoundOrSelf()
+
val keyRowAdapter = findRowAdapter(
typeMirror = keyTypeArg,
query = query,
- columnName = null
+ // No need to account for @MapInfo since nested maps did not support
+ // this now deprecated annotation anyway.
+ columnName = getMapColumnName(context, query, keyTypeArg)
) ?: return null
- val valueTypeArg = mapValueTypeArg.typeArguments[1].extendsBoundOrSelf()
val valueMapAdapter = findMapValueResultAdapter(
- query, mapInfo, valueTypeArg
+ query = query,
+ mapInfo = mapInfo,
+ mapValueTypeArg = valueTypeArg
) ?: return null
return MapValueResultAdapter.NestedMapValueResultAdapter(
keyRowAdapter = keyRowAdapter,
@@ -837,17 +869,19 @@
mapValueResultAdapter = valueMapAdapter
)
} else {
+ val mappedValueColumnName = getMapColumnName(context, query, mapValueTypeArg)
+ ?: mapInfo?.valueColumnName
val valueRowAdapter = findRowAdapter(
typeMirror = mapValueTypeArg,
query = query,
- columnName = mapInfo?.valueColumnName
+ columnName = mappedValueColumnName
) ?: return null
validateMapValueTypeArg(
context = context,
valueTypeArg = mapValueTypeArg,
valueReader = findCursorValueReader(mapValueTypeArg, null),
- mapInfo = mapInfo
+ valueColumnName = mappedValueColumnName
)
return MapValueResultAdapter.EndMapValueResultAdapter(
valueRowAdapter = valueRowAdapter,
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt
index 3d77078..a758ff4 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MapValueResultAdapter.kt
@@ -340,8 +340,12 @@
language == CodeLanguage.KOTLIN &&
valueTypeArg.nullability == XNullability.NONNULL
) {
- // TODO(b/249984504): Generate / output a better message.
- addStatement("error(%S)", "Missing value for a key.")
+ addStatement(
+ "error(%S)",
+ "The column(s) of the map value object of type " +
+ "'$valueTypeArg' are NULL but the map's value type " +
+ "argument expect it to be NON-NULL"
+ )
} else {
genPutValueCode.invoke("null", false)
addStatement("continue")
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt
index c5791df..1d71248 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/MultimapQueryResultAdapter.kt
@@ -16,9 +16,11 @@
package androidx.room.solver.query.result
+import androidx.room.MapColumn
import androidx.room.compiler.codegen.CodeLanguage
import androidx.room.compiler.codegen.XClassName
import androidx.room.compiler.codegen.XCodeBlock
+import androidx.room.compiler.codegen.asClassName
import androidx.room.compiler.processing.XType
import androidx.room.ext.CollectionTypeNames
import androidx.room.ext.CommonTypeNames
@@ -30,8 +32,8 @@
import androidx.room.processor.ProcessorErrors.AmbiguousColumnLocation.MAP_INFO
import androidx.room.processor.ProcessorErrors.AmbiguousColumnLocation.POJO
import androidx.room.solver.types.CursorValueReader
+import androidx.room.verifier.ColumnInfo
import androidx.room.vo.ColumnIndexVar
-import androidx.room.vo.MapInfo
import androidx.room.vo.Warning
/**
@@ -118,14 +120,14 @@
companion object {
/**
- * Checks if the @MapInfo annotation is needed for clarification regarding the key type
+ * Checks if the @MapColumn annotation is needed for clarification regarding the key type
* arg of a Map return type.
*/
fun validateMapKeyTypeArg(
context: Context,
keyTypeArg: XType,
keyReader: CursorValueReader?,
- mapInfo: MapInfo?,
+ keyColumnName: String?,
) {
if (!keyTypeArg.implementsEqualsAndHashcode()) {
context.logger.w(
@@ -136,10 +138,10 @@
)
}
- val hasKeyColumnName = mapInfo?.keyColumnName?.isNotEmpty() ?: false
+ val hasKeyColumnName = keyColumnName?.isNotEmpty() ?: false
if (!hasKeyColumnName && keyReader != null) {
context.logger.e(
- ProcessorErrors.keyMayNeedMapInfo(
+ ProcessorErrors.mayNeedMapColumn(
keyTypeArg.asTypeName().toString(context.codeLanguage)
)
)
@@ -147,24 +149,68 @@
}
/**
- * Checks if the @MapInfo annotation is needed for clarification regarding the value type
+ * Checks if the @MapColumn annotation is needed for clarification regarding the value type
* arg of a Map return type.
*/
fun validateMapValueTypeArg(
context: Context,
valueTypeArg: XType,
valueReader: CursorValueReader?,
- mapInfo: MapInfo?,
+ valueColumnName: String?,
) {
- val hasValueColumnName = mapInfo?.valueColumnName?.isNotEmpty() ?: false
+ val hasValueColumnName = valueColumnName?.isNotEmpty() ?: false
if (!hasValueColumnName && valueReader != null) {
context.logger.e(
- ProcessorErrors.valueMayNeedMapInfo(
+ ProcessorErrors.mayNeedMapColumn(
valueTypeArg.asTypeName().toString(context.codeLanguage)
)
)
}
}
+
+ /**
+ * Retrieves the `columnName` value from a @MapColumn annotation.
+ */
+ fun getMapColumnName(context: Context, query: ParsedQuery, type: XType): String? {
+ val resultColumns = query.resultInfo?.columns
+ val resultTableAliases = query.tables.associate { it.name to it.alias }
+ val annotation = type.getAnnotation(MapColumn::class.asClassName()) ?: return null
+
+ val mapColumnName = annotation.getAsString("columnName")
+ val mapColumnTableName = annotation.getAsString("tableName")
+
+ fun List<ColumnInfo>.contains(
+ columnName: String,
+ tableName: String?
+ ) = any { resultColumn ->
+ val resultTableAlias = resultColumn.originTable?.let {
+ resultTableAliases[it] ?: it
+ }
+ resultColumn.name == columnName && (
+ if (!tableName.isNullOrEmpty()) {
+ resultTableAlias == tableName || resultColumn.originTable == tableName
+ } else true)
+ }
+
+ if (resultColumns != null) {
+ // Disambiguation check for MapColumn
+ if (!resultColumns.contains(mapColumnName, mapColumnTableName)) {
+ val errorColumn = if (mapColumnTableName.isNotEmpty()) {
+ "$mapColumnTableName."
+ } else {
+ ""
+ } + mapColumnName
+ context.logger.e(
+ ProcessorErrors.cannotMapSpecifiedColumn(
+ errorColumn,
+ resultColumns.map { it.name },
+ MapColumn::class.java.simpleName
+ )
+ )
+ }
+ }
+ return mapColumnName
+ }
}
/**
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt
index b9fdcbb..519ff4a 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/query/result/SingleItemQueryResultAdapter.kt
@@ -41,8 +41,11 @@
type.nullability == XNullability.NONNULL &&
defaultValue == "null"
) {
- // TODO(b/249984504): Generate / output a better message.
- addStatement("error(%S)", "Cursor was empty, but expected a single item.")
+ addStatement(
+ "error(%S)", "The query result was empty, but expected a single row to " +
+ "return a NON-NULL object of " +
+ "type <${type.asTypeName().toString(language)}>."
+ )
} else {
addStatement("%L = %L", outVarName, rowAdapter.out.defaultValue())
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt
index 7d2196e..03c641c 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/NullAwareTypeConverters.kt
@@ -93,7 +93,7 @@
private fun XCodeBlock.Builder.addIllegalStateException() {
val typeName = from.asTypeName().copy(nullable = false).toString(language)
- val message = "Expected non-null $typeName, but it was null."
+ val message = "Expected NON-NULL '$typeName', but it was NULL."
when (language) {
CodeLanguage.JAVA -> {
addStatement(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt
index cc2d6ee..831520d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/solver/types/ValueClassConverterWrapper.kt
@@ -80,13 +80,13 @@
scope.builder.apply {
val propertyName = scope.getTmpVar("_$valuePropertyName")
val assignmentBlock = if (out.nullability == XNullability.NONNULL) {
- // TODO(b/249984504): Generate / output a better message.
XCodeBlock.of(
scope.language,
"checkNotNull(%L.%L) { %S }",
valueVarName,
valuePropertyName,
- "Cannot bind nullable value of inline class to a NOT NULL column."
+ "Cannot bind NULLABLE value '$valuePropertyName' of inline " +
+ "class '$out' to a NOT NULL column."
)
} else {
XCodeBlock.of(
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
index dce1f83..eceddad 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/vo/RelationCollector.kt
@@ -174,8 +174,13 @@
addStatement("%L = %L.get(%L)", tmpRelationVar, varName, tmpKeyVar)
if (language == CodeLanguage.KOTLIN && relation.field.nonNull) {
beginControlFlow("if (%L == null)", tmpRelationVar)
- // TODO(b/249984504): Generate / output a better message.
- addStatement("error(%S)", "Missing relationship item.")
+ addStatement(
+ "error(%S)",
+ "Relationship item '${relation.field.name}' was expected to" +
+ " be NON-NULL but is NULL in @Relation involving " +
+ "a parent column named '${relation.parentField.columnName}' and " +
+ "entityColumn named '${relation.entityField.columnName}'."
+ )
endControlFlow()
}
}
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt
index d1d1379..204bc48 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityDeletionAdapterWriter.kt
@@ -60,7 +60,7 @@
XFunSpec.builder(
language = language,
name = "createQuery",
- visibility = VisibilityModifier.PUBLIC,
+ visibility = VisibilityModifier.PROTECTED,
isOverride = true
).apply {
returns(CommonTypeNames.STRING)
@@ -73,7 +73,7 @@
XFunSpec.builder(
language = language,
name = "bind",
- visibility = VisibilityModifier.PUBLIC,
+ visibility = VisibilityModifier.PROTECTED,
isOverride = true
).apply {
val stmtParam = "statement"
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt
index 5e2b01f..3a6d684 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityInsertionAdapterWriter.kt
@@ -75,7 +75,7 @@
XFunSpec.builder(
language = language,
name = "createQuery",
- visibility = VisibilityModifier.PUBLIC,
+ visibility = VisibilityModifier.PROTECTED,
isOverride = true
).apply {
returns(CommonTypeNames.STRING)
@@ -105,7 +105,7 @@
XFunSpec.builder(
language = language,
name = "bind",
- visibility = VisibilityModifier.PUBLIC,
+ visibility = VisibilityModifier.PROTECTED,
isOverride = true
).apply {
returns(XTypeName.UNIT_VOID)
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt
index c7f487c..f06592d 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/EntityUpdateAdapterWriter.kt
@@ -53,7 +53,7 @@
XFunSpec.builder(
language = language,
name = "createQuery",
- visibility = VisibilityModifier.PUBLIC,
+ visibility = VisibilityModifier.PROTECTED,
isOverride = true
).apply {
returns(CommonTypeNames.STRING)
@@ -80,7 +80,7 @@
XFunSpec.builder(
language = language,
name = "bind",
- visibility = VisibilityModifier.PUBLIC,
+ visibility = VisibilityModifier.PROTECTED,
isOverride = true
).apply {
val stmtParam = "statement"
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt b/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
index 8b856c3..b523301 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
@@ -373,10 +373,10 @@
typeName.nullability == XNullability.NONNULL &&
defaultValue == "null"
) {
- // TODO(b/249984504): Generate / output a better message.
addStatement(
"error(%S)",
- "Missing column '${field.columnName}' for a non null value."
+ "Missing value for a NON-NULL column '${field.columnName}', " +
+ "found NULL value instead."
)
} else {
addStatement("%L = %L", tmpField, defaultValue)
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
index 13d0293..9c40b99 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/QueryMethodProcessorTest.kt
@@ -41,11 +41,11 @@
import androidx.room.ext.RxJava3TypeNames
import androidx.room.parser.QueryType
import androidx.room.parser.Table
+import androidx.room.processor.ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
import androidx.room.processor.ProcessorErrors.DO_NOT_USE_GENERIC_IMMUTABLE_MULTIMAP
import androidx.room.processor.ProcessorErrors.MAP_INFO_MUST_HAVE_AT_LEAST_ONE_COLUMN_PROVIDED
import androidx.room.processor.ProcessorErrors.cannotFindQueryResultAdapter
-import androidx.room.processor.ProcessorErrors.keyMayNeedMapInfo
-import androidx.room.processor.ProcessorErrors.valueMayNeedMapInfo
+import androidx.room.processor.ProcessorErrors.mayNeedMapColumn
import androidx.room.solver.query.result.DataSourceFactoryQueryResultBinder
import androidx.room.solver.query.result.ListQueryResultAdapter
import androidx.room.solver.query.result.LiveDataQueryResultBinder
@@ -1305,7 +1305,7 @@
DAO_PREFIX + input.joinToString("\n") + DAO_SUFFIX
)
val commonSources = listOf(
- COMMON.LIVE_DATA, COMMON.COMPUTABLE_LIVE_DATA, COMMON.USER, COMMON.BOOK,
+ COMMON.LIVE_DATA, COMMON.COMPUTABLE_LIVE_DATA, COMMON.USER, COMMON.BOOK, COMMON.PAGE,
COMMON.NOT_AN_ENTITY, COMMON.ARTIST, COMMON.SONG, COMMON.IMAGE, COMMON.IMAGE_FORMAT,
COMMON.CONVERTER
)
@@ -1511,6 +1511,131 @@
}
@Test
+ fun testUseMapColumnWithColumnName() {
+ if (!enableVerification) {
+ return
+ }
+ singleQueryMethod<ReadQueryMethod>(
+ """
+ @SuppressWarnings(
+ {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+ )
+ @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid")
+ abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap();
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
+ @Test
+ fun testUseMapColumnWithColumnNameWrongTableName() {
+ if (!enableVerification) {
+ return
+ }
+ singleQueryMethod<ReadQueryMethod>(
+ """
+ @SuppressWarnings(
+ {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+ )
+ @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid")
+ abstract Map<@MapColumn(columnName = "uid", tableName = "NoName") Integer, Book> getMultimap();
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasErrorContaining(
+ "Column specified in the provided @MapColumn " +
+ "annotation must be present in the query."
+ )
+ }
+ }
+ }
+
+ @Test
+ fun testUseNestedMapColumnWithColumnName() {
+ if (!enableVerification) {
+ return
+ }
+ singleQueryMethod<ReadQueryMethod>(
+ """
+ @SuppressWarnings(
+ {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+ )
+ @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid JOIN Page on b.uid == pBid")
+ abstract Map<@MapColumn(columnName = "uid") Integer, Map<Book, @MapColumn(columnName = "pBid") Integer>> getMultimap();
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
+ @Test
+ fun testUseNestedMapColumnWithNestedKeyColumnName() {
+ if (!enableVerification) {
+ return
+ }
+ singleQueryMethod<ReadQueryMethod>(
+ """
+ @SuppressWarnings(
+ {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+ )
+ @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid JOIN Page on b.uid == pBid")
+ abstract Map<@MapColumn(columnName = "uid") Integer, Map<@MapColumn(columnName = "bookId") Integer, @MapColumn(columnName = "pBid") Integer>> getMultimap();
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
+ @Test
+ fun testUseMapColumnWithColumnAlias() {
+ if (!enableVerification) {
+ return
+ }
+ singleQueryMethod<ReadQueryMethod>(
+ """
+ @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
+ @Query("SELECT name, (SELECT count(*) FROM User u JOIN Book b ON u.uid == b.uid) "
+ + "AS bookCount FROM User")
+ abstract Map<@MapColumn(columnName = "name") String, @MapColumn(columnName = "bookCount") Integer> getMultimap();
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
+ @Test
+ fun testCannotHaveMapInfoAndMapColumn() {
+ if (!enableVerification) {
+ return
+ }
+ singleQueryMethod<ReadQueryMethod>(
+ """
+ @SuppressWarnings(
+ {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+ )
+ @MapInfo(keyColumn = "uid", keyTable = "u")
+ @Query("SELECT * FROM User u JOIN Book b ON u.uid == b.uid")
+ abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap();
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasErrorContaining(
+ CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+ )
+ }
+ }
+ }
+
+ @Test
fun testDoesNotImplementEqualsAndHashcodeQuery() {
singleQueryMethod<ReadQueryMethod>(
"""
@@ -1539,7 +1664,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+ mayNeedMapColumn(STRING.canonicalName)
)
}
}
@@ -1556,7 +1681,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+ mayNeedMapColumn(STRING.canonicalName)
)
}
}
@@ -1572,7 +1697,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+ mayNeedMapColumn(STRING.canonicalName)
)
}
}
@@ -1588,7 +1713,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo(CommonTypeNames.STRING.canonicalName)
+ mayNeedMapColumn(STRING.canonicalName)
)
}
}
@@ -1604,7 +1729,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+ mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
)
}
}
@@ -1620,7 +1745,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+ mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
)
}
}
@@ -1636,7 +1761,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+ mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
)
}
}
@@ -1653,7 +1778,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- keyMayNeedMapInfo("java.util.Date")
+ mayNeedMapColumn("java.util.Date")
)
}
}
@@ -1670,7 +1795,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- valueMayNeedMapInfo("java.util.Date")
+ mayNeedMapColumn("java.util.Date")
)
}
}
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
index 291267e..805c6ea 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/processor/RawQueryMethodProcessorTest.kt
@@ -423,7 +423,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo(
+ ProcessorErrors.mayNeedMapColumn(
CommonTypeNames.STRING.canonicalName
)
)
@@ -441,7 +441,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo(
+ ProcessorErrors.mayNeedMapColumn(
CommonTypeNames.STRING.canonicalName
)
)
@@ -459,7 +459,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo(
+ ProcessorErrors.mayNeedMapColumn(
CommonTypeNames.STRING.canonicalName
)
)
@@ -477,7 +477,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+ ProcessorErrors.mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
)
}
}
@@ -493,7 +493,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+ ProcessorErrors.mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
)
}
}
@@ -509,7 +509,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo(XTypeName.BOXED_LONG.canonicalName)
+ ProcessorErrors.mayNeedMapColumn(XTypeName.BOXED_LONG.canonicalName)
)
}
}
@@ -526,7 +526,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.keyMayNeedMapInfo("java.util.Date")
+ ProcessorErrors.mayNeedMapColumn("java.util.Date")
)
}
}
@@ -543,7 +543,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo("java.util.Date")
+ ProcessorErrors.mayNeedMapColumn("java.util.Date")
)
}
}
@@ -560,7 +560,7 @@
) { _, invocation ->
invocation.assertCompilationResult {
hasErrorContaining(
- ProcessorErrors.valueMayNeedMapInfo(
+ ProcessorErrors.mayNeedMapColumn(
CommonTypeNames.STRING.canonicalName
)
)
@@ -569,6 +569,47 @@
}
@Test
+ fun testUseMapColumnWithColumnName() {
+ singleQueryMethod(
+ """
+ @SuppressWarnings(
+ {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+ )
+ @RawQuery
+ abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap(
+ SupportSQLiteQuery query
+ );
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasNoWarnings()
+ }
+ }
+ }
+
+ @Test
+ fun testCannotHaveMapInfoAndMapColumn() {
+ singleQueryMethod(
+ """
+ @SuppressWarnings(
+ {RoomWarnings.CURSOR_MISMATCH, RoomWarnings.AMBIGUOUS_COLUMN_IN_RESULT}
+ )
+ @MapInfo(keyColumn = "uid", keyTable = "u")
+ @RawQuery
+ abstract Map<@MapColumn(columnName = "uid") Integer, Book> getMultimap(
+ SupportSQLiteQuery query
+ );
+ """
+ ) { _, invocation ->
+ invocation.assertCompilationResult {
+ hasErrorContaining(
+ ProcessorErrors.CANNOT_USE_MAP_COLUMN_AND_MAP_INFO_SIMULTANEOUSLY
+ )
+ }
+ }
+ }
+
+ @Test
fun suspendReturnsDeferredType() {
listOf(
"${RxJava2TypeNames.FLOWABLE.canonicalName}<Int>",
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt b/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
index b98bcfd6..688ff71 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/testing/test_util.kt
@@ -78,6 +78,11 @@
val BOOK by lazy {
loadJavaCode("common/input/Book.java", "foo.bar.Book")
}
+
+ val PAGE by lazy {
+ loadJavaCode("common/input/Page.java", "foo.bar.Page")
+ }
+
val NOT_AN_ENTITY by lazy {
loadJavaCode("common/input/NotAnEntity.java", "foo.bar.NotAnEntity")
}
diff --git a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
index 9c2d88c..ca22005 100644
--- a/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
+++ b/room/room-compiler/src/test/kotlin/androidx/room/writer/DaoKotlinCodeGenTest.kt
@@ -1483,6 +1483,7 @@
@Query("SELECT * FROM Artist JOIN Song ON Artist.artistId = Song.artistKey")
fun getArtistWithSongs(): Map<Artist, List<Song>>
+ @Suppress("DEPRECATION") // For @MapInfo
@MapInfo(valueColumn = "songCount")
@Query(
"SELECT Artist.*, COUNT(songId) as songCount " +
@@ -1492,6 +1493,7 @@
fun getArtistSongCount(): Map<Artist, Int>
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
+ @Suppress("DEPRECATION") // For @MapInfo
@MapInfo(valueColumn = "songId")
@Query("SELECT * FROM Artist JOIN Song ON Artist.artistId = Song.artistKey")
fun getArtistWithSongIds(): Map<Artist, List<String>>
diff --git a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java b/room/room-compiler/src/test/test-data/common/input/Page.java
similarity index 61%
copy from lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
copy to room/room-compiler/src/test/test-data/common/input/Page.java
index 31d0e6f..e9937cb 100644
--- a/lifecycle/lifecycle-common/src/test/java/androidx/lifecycle/observers/Interface1.java
+++ b/room/room-compiler/src/test/test-data/common/input/Page.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,14 +14,11 @@
* limitations under the License.
*/
-package androidx.lifecycle.observers;
-
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleObserver;
-
-@SuppressWarnings("deprecation")
-public interface Interface1 extends LifecycleObserver {
-
- @androidx.lifecycle.OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
- void onCreate();
+package foo.bar;
+import androidx.room.*;
+@Entity
+public class Page {
+ @PrimaryKey
+ int pageId;
+ int pBid;
}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
index 598d267..31272dc 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/DeletionDao.java
@@ -43,24 +43,24 @@
this.__deletionAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "DELETE FROM `User` WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
}
};
this.__deletionAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "DELETE FROM `MultiPKeyEntity` WHERE `name` = ? AND `lastName` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
final MultiPKeyEntity entity) {
if (entity.name == null) {
statement.bindNull(1);
@@ -77,12 +77,12 @@
this.__deletionAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "DELETE FROM `Book` WHERE `bookId` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
statement.bindLong(1, entity.bookId);
}
};
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
index e3b6103..5dbb7eb 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpdateDao.java
@@ -43,12 +43,12 @@
this.__updateAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE OR ABORT `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
if (entity.name == null) {
statement.bindNull(2);
@@ -67,12 +67,12 @@
this.__updateAdapterOfUser_1 = new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
if (entity.name == null) {
statement.bindNull(2);
@@ -91,12 +91,12 @@
this.__updateAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE OR ABORT `MultiPKeyEntity` SET `name` = ?,`lastName` = ? WHERE `name` = ? AND `lastName` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
final MultiPKeyEntity entity) {
if (entity.name == null) {
statement.bindNull(1);
@@ -123,12 +123,12 @@
this.__updateAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE OR ABORT `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
statement.bindLong(3, entity.bookId);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java
index 1e7255b..4d4875a 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/UpsertDao.java
@@ -28,12 +28,12 @@
this.__upsertionAdapterOfUser = new EntityUpsertionAdapter<User>(new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
if (entity.name == null) {
statement.bindNull(2);
@@ -50,12 +50,12 @@
}, new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
if (entity.name == null) {
statement.bindNull(2);
@@ -74,24 +74,24 @@
this.__upsertionAdapterOfBook = new EntityUpsertionAdapter<Book>(new EntityInsertionAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
}
}, new EntityDeletionOrUpdateAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
statement.bindLong(3, entity.bookId);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java
index ddbbe73..3287dd2 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/javac/WriterDao.java
@@ -30,12 +30,12 @@
this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT OR ABORT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
if (entity.name == null) {
statement.bindNull(2);
@@ -53,12 +53,12 @@
this.__insertionAdapterOfUser_1 = new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT OR REPLACE INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
if (entity.name == null) {
statement.bindNull(2);
@@ -76,12 +76,12 @@
this.__insertionAdapterOfUser_2 = new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final User entity) {
statement.bindLong(1, entity.uid);
if (entity.name == null) {
statement.bindNull(2);
@@ -99,12 +99,12 @@
this.__insertionAdapterOfBook = new EntityInsertionAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT OR ABORT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
+ protected void bind(@NonNull final SupportSQLiteStatement statement, final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
index 4fa7155..45fee3b 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/DeletionDao.java
@@ -43,12 +43,12 @@
this.__deletionAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "DELETE FROM `User` WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
}
@@ -56,12 +56,12 @@
this.__deletionAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "DELETE FROM `MultiPKeyEntity` WHERE `name` = ? AND `lastName` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final MultiPKeyEntity entity) {
statement.bindString(1, entity.name);
statement.bindString(2, entity.lastName);
@@ -70,12 +70,12 @@
this.__deletionAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "DELETE FROM `Book` WHERE `bookId` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final Book entity) {
statement.bindLong(1, entity.bookId);
}
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
index 571e245..1fb23be 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpdateDao.java
@@ -43,12 +43,12 @@
this.__updateAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE OR ABORT `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
statement.bindString(2, entity.name);
@@ -60,12 +60,12 @@
this.__updateAdapterOfUser_1 = new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
statement.bindString(2, entity.name);
@@ -77,12 +77,12 @@
this.__updateAdapterOfMultiPKeyEntity = new EntityDeletionOrUpdateAdapter<MultiPKeyEntity>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE OR ABORT `MultiPKeyEntity` SET `name` = ?,`lastName` = ? WHERE `name` = ? AND `lastName` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final MultiPKeyEntity entity) {
statement.bindString(1, entity.name);
statement.bindString(2, entity.lastName);
@@ -93,12 +93,12 @@
this.__updateAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE OR ABORT `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
index 8a1374c..80b1ba9 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/UpsertDao.java
@@ -28,12 +28,12 @@
this.__upsertionAdapterOfUser = new EntityUpsertionAdapter<User>(new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
statement.bindString(2, entity.name);
@@ -43,12 +43,12 @@
}, new EntityDeletionOrUpdateAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE `User` SET `uid` = ?,`name` = ?,`lastName` = ?,`ageColumn` = ? WHERE `uid` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
statement.bindString(2, entity.name);
@@ -60,12 +60,12 @@
this.__upsertionAdapterOfBook = new EntityUpsertionAdapter<Book>(new EntityInsertionAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
@@ -73,12 +73,12 @@
}, new EntityDeletionOrUpdateAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "UPDATE `Book` SET `bookId` = ?,`uid` = ? WHERE `bookId` = ?";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
diff --git a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
index 54443ae..a0601f1 100644
--- a/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
+++ b/room/room-compiler/src/test/test-data/daoWriter/output/ksp/WriterDao.java
@@ -30,12 +30,12 @@
this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT OR ABORT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
statement.bindString(2, entity.name);
@@ -46,12 +46,12 @@
this.__insertionAdapterOfUser_1 = new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT OR REPLACE INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
statement.bindString(2, entity.name);
@@ -62,12 +62,12 @@
this.__insertionAdapterOfUser_2 = new EntityInsertionAdapter<User>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT INTO `User` (`uid`,`name`,`lastName`,`ageColumn`) VALUES (?,?,?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final User entity) {
statement.bindLong(1, entity.uid);
statement.bindString(2, entity.name);
@@ -78,12 +78,12 @@
this.__insertionAdapterOfBook = new EntityInsertionAdapter<Book>(__db) {
@Override
@NonNull
- public String createQuery() {
+ protected String createQuery() {
return "INSERT OR ABORT INTO `Book` (`bookId`,`uid`) VALUES (?,?)";
}
@Override
- public void bind(@NonNull final SupportSQLiteStatement statement,
+ protected void bind(@NonNull final SupportSQLiteStatement statement,
@NonNull final Book entity) {
statement.bindLong(1, entity.bookId);
statement.bindLong(2, entity.uid);
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt
index d306558..1caa291 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/abstractClassWithParam.kt
@@ -35,7 +35,7 @@
_tmpPk = _cursor.getInt(_cursorIndexOfPk)
_result = MyEntity(_tmpPk)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt
index d415b37..27b158e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/arrayParameterAdapter.kt
@@ -51,7 +51,7 @@
_tmpId = _cursor.getString(_cursorIndexOfId)
_result = MyEntity(_tmpId)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -88,7 +88,7 @@
_tmpId = _cursor.getString(_cursorIndexOfId)
_result = MyEntity(_tmpId)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -125,7 +125,7 @@
_tmpId = _cursor.getString(_cursorIndexOfId)
_result = MyEntity(_tmpId)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -158,7 +158,7 @@
_tmpId = _cursor.getString(_cursorIndexOfId)
_result = MyEntity(_tmpId)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -195,7 +195,7 @@
_tmpId = _cursor.getString(_cursorIndexOfId)
_result = MyEntity(_tmpId)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -228,7 +228,7 @@
_tmpId = _cursor.getString(_cursorIndexOfId)
_result = MyEntity(_tmpId)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -265,7 +265,7 @@
_tmpId = _cursor.getString(_cursorIndexOfId)
_result = MyEntity(_tmpId)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt
index 3b22d23..a8234c8 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/basicParameterAdapter_string.kt
@@ -37,7 +37,7 @@
_tmpString = _cursor.getString(_cursorIndexOfString)
_result = MyEntity(_tmpString)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -65,7 +65,7 @@
_tmpString = _cursor.getString(_cursorIndexOfString)
_result = MyEntity(_tmpString)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt
index fd018379..7cfc96d 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx2.kt
@@ -64,7 +64,7 @@
_tmpOther = _cursor.getString(_cursorIndexOfOther)
_result = MyEntity(_tmpPk,_tmpOther)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -110,7 +110,7 @@
_tmpOther = _cursor.getString(_cursorIndexOfOther)
_result = MyEntity(_tmpPk,_tmpOther)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt
index 48492a3..bbd0db3 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/callableQuery_rx3.kt
@@ -64,7 +64,7 @@
_tmpOther = _cursor.getString(_cursorIndexOfOther)
_result = MyEntity(_tmpPk,_tmpOther)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -110,7 +110,7 @@
_tmpOther = _cursor.getString(_cursorIndexOfOther)
_result = MyEntity(_tmpPk,_tmpOther)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt
index 1d1a468..3c8a547 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/collectionParameterAdapter_string.kt
@@ -50,7 +50,7 @@
_tmpString = _cursor.getString(_cursorIndexOfString)
_result = MyEntity(_tmpString)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -87,7 +87,7 @@
_tmpString = _cursor.getString(_cursorIndexOfString)
_result = MyEntity(_tmpString)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -124,7 +124,7 @@
_tmpString = _cursor.getString(_cursorIndexOfString)
_result = MyEntity(_tmpString)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -157,7 +157,7 @@
_tmpString = _cursor.getString(_cursorIndexOfString)
_result = MyEntity(_tmpString)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt
index b959c1c..ef15633 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutineResultBinder.kt
@@ -41,7 +41,7 @@
_tmpPk = _cursor.getInt(_cursorIndexOfPk)
_result = MyEntity(_tmpPk)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
index 3cf1b4c..e09976c 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/coroutines.kt
@@ -65,7 +65,7 @@
_tmpOther = _cursor.getString(_cursorIndexOfOther)
_result = MyEntity(_tmpPk,_tmpOther)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
index e7ff72b..2f5a0cc 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_boxedPrimitiveBridge.kt
@@ -67,7 +67,7 @@
_tmpPk = _cursor.getLong(_cursorIndexOfPk)
_result = MyEntity(_tmpPk)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt
index f2b5842..a2792d8 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/delegatingFunctions_defaultImplBridge.kt
@@ -36,7 +36,7 @@
_tmpPk = _cursor.getLong(_cursorIndexOfPk)
_result = MyEntity(_tmpPk)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt
index 233b23a..890f85e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/deleteOrUpdateMethodAdapter.kt
@@ -22,17 +22,17 @@
init {
this.__db = __db
this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+ protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk)
}
}
this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE OR ABORT `MyEntity` SET `pk` = ?,`data` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk)
statement.bindString(2, entity.data)
statement.bindLong(3, entity.pk)
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt
index d00f043..bbc3dc0 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/entityRowAdapter.kt
@@ -27,10 +27,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`valuePrimitive`,`valueBoolean`,`valueString`,`valueNullableString`,`variablePrimitive`,`variableNullableBoolean`,`variableString`,`variableNullableString`) VALUES (?,?,?,?,?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.valuePrimitive)
val _tmp: Int = if (entity.valueBoolean) 1 else 0
statement.bindLong(2, _tmp.toLong())
@@ -81,7 +81,7 @@
if (_cursor.moveToFirst()) {
_result = __entityCursorConverter_MyEntity(_cursor)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
@@ -117,7 +117,7 @@
}
val _tmpValueString: String
if (_cursorIndexOfValueString == -1) {
- error("Missing column 'valueString' for a non null value.")
+ error("Missing value for a NON-NULL column 'valueString', found NULL value instead.")
} else {
_tmpValueString = cursor.getString(_cursorIndexOfValueString)
}
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt
index 3d51fc4..70371f9 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/guavaCallable.kt
@@ -42,26 +42,26 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}
this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+ protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
}
}
this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
@@ -69,18 +69,18 @@
}
this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
@@ -181,7 +181,7 @@
_tmpOther = _cursor.getString(_cursorIndexOfOther)
_result = MyEntity(_tmpPk,_tmpOther)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt
index 246af07..f7ce132 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/insertOrUpsertMethodAdapter.kt
@@ -25,28 +25,28 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`data`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk)
statement.bindString(2, entity.data)
}
}
this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT INTO `MyEntity` (`pk`,`data`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk)
statement.bindString(2, entity.data)
}
}, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE `MyEntity` SET `pk` = ?,`data` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk)
statement.bindString(2, entity.data)
statement.bindLong(3, entity.pk)
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt
index 0c57f0e..f587b69 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_boolean.kt
@@ -26,10 +26,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`boolean`,`nullableBoolean`) VALUES (?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
val _tmp: Int = if (entity.boolean) 1 else 0
statement.bindLong(2, _tmp.toLong())
@@ -82,7 +82,7 @@
_tmpNullableBoolean = _tmp_1?.let { it != 0 }
_result = MyEntity(_tmpPk,_tmpBoolean,_tmpNullableBoolean)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt
index f369507..5c83c9e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_byteArray.kt
@@ -26,10 +26,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`byteArray`,`nullableByteArray`) VALUES (?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindBlob(2, entity.byteArray)
val _tmpNullableByteArray: ByteArray? = entity.nullableByteArray
@@ -76,7 +76,7 @@
}
_result = MyEntity(_tmpPk,_tmpByteArray,_tmpNullableByteArray)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt
index 6e7794e..e509e2e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter.kt
@@ -27,10 +27,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
val _tmp: String = __fooConverter.toString(entity.foo)
statement.bindString(2, _tmp)
@@ -67,7 +67,7 @@
_tmpFoo = __fooConverter.fromString(_tmp)
_result = MyEntity(_tmpPk,_tmpFoo)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt
index 96566e6..d88a2e0 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_composite.kt
@@ -25,10 +25,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`bar`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
val _tmp: Foo = FooBarConverter.toFoo(entity.bar)
val _tmp_1: String = FooBarConverter.toString(_tmp)
@@ -67,7 +67,7 @@
_tmpBar = FooBarConverter.fromFoo(_tmp_1)
_result = MyEntity(_tmpPk,_tmpBar)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt
index 0ba6f82..d5da42b 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_internalVisibility.kt
@@ -27,10 +27,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
val _tmp: String = __fooConverter.toString(entity.foo)
statement.bindString(2, _tmp)
@@ -67,7 +67,7 @@
_tmpFoo = __fooConverter.fromString(_tmp)
_result = MyEntity(_tmpPk,_tmpFoo)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt
index 0ea0420..5480240 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_nullAware.kt
@@ -25,10 +25,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`,`bar`) VALUES (?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
val _tmp: String? = FooBarConverter.toString(entity.foo)
if (_tmp == null) {
@@ -80,7 +80,7 @@
}
val _tmp_1: Foo? = FooBarConverter.fromString(_tmp)
if (_tmp_1 == null) {
- error("Expected non-null Foo, but it was null.")
+ error("Expected NON-NULL 'Foo', but it was NULL.")
} else {
_tmpFoo = _tmp_1
}
@@ -99,13 +99,13 @@
_tmp_4 = FooBarConverter.fromFoo(_tmp_3)
}
if (_tmp_4 == null) {
- error("Expected non-null Bar, but it was null.")
+ error("Expected NON-NULL 'Bar', but it was NULL.")
} else {
_tmpBar = _tmp_4
}
_result = MyEntity(_tmpPk,_tmpFoo,_tmpBar)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt
index 3895395..e6115de 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_customTypeConverter_provided.kt
@@ -31,10 +31,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`foo`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
val _tmp: String = __fooConverter().toString(entity.foo)
statement.bindString(2, _tmp)
@@ -71,7 +71,7 @@
_tmpFoo = __fooConverter().fromString(_tmp)
_result = MyEntity(_tmpPk,_tmpFoo)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt
index b9a01bc..6a0e2c6 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_embedded.kt
@@ -26,10 +26,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`numberData`,`stringData`,`nullablenumberData`,`nullablestringData`) VALUES (?,?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
val _tmpFoo: Foo = entity.foo
statement.bindLong(2, _tmpFoo.numberData)
@@ -91,7 +91,7 @@
}
_result = MyEntity(_tmpPk,_tmpFoo,_tmpNullableFoo)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt
index a6f83a7..7dc5a23 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_enum.kt
@@ -26,10 +26,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`enum`,`nullableEnum`) VALUES (?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, __Fruit_enumToString(entity.enum))
val _tmpNullableEnum: Fruit? = entity.nullableEnum
@@ -76,7 +76,7 @@
}
_result = MyEntity(_tmpPk,_tmpEnum,_tmpNullableEnum)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt
index db1f98c..3b6eb74 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_internalVisibility.kt
@@ -26,10 +26,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`internalVal`,`internalVar`,`internalSetterVar`) VALUES (?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindLong(2, entity.internalVal)
statement.bindLong(3, entity.internalVar)
@@ -69,7 +69,7 @@
_result.internalVar = _cursor.getLong(_cursorIndexOfInternalVar)
_result.internalSetterVar = _cursor.getLong(_cursorIndexOfInternalSetterVar)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt
index 320a33b..138324c 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_otherModule.kt
@@ -26,10 +26,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`primitive`,`string`,`nullableString`,`fieldString`,`nullableFieldString`,`variablePrimitive`,`variableString`,`variableNullableString`,`variableFieldString`,`variableNullableFieldString`) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindLong(2, entity.primitive)
statement.bindString(3, entity.string)
@@ -136,7 +136,7 @@
_cursor.getString(_cursorIndexOfVariableNullableFieldString)
}
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt
index 520ecbb..45ad899 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives.kt
@@ -31,10 +31,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`int`,`short`,`byte`,`long`,`char`,`float`,`double`) VALUES (?,?,?,?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.int.toLong())
statement.bindLong(2, entity.short.toLong())
statement.bindLong(3, entity.byte.toLong())
@@ -88,7 +88,7 @@
_tmpDouble = _cursor.getDouble(_cursorIndexOfDouble)
_result = MyEntity(_tmpInt,_tmpShort,_tmpByte,_tmpLong,_tmpChar,_tmpFloat,_tmpDouble)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt
index 109df70..a970c59 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_primitives_nullable.kt
@@ -31,10 +31,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`int`,`short`,`byte`,`long`,`char`,`float`,`double`) VALUES (?,?,?,?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
val _tmpInt: Int? = entity.int
if (_tmpInt == null) {
statement.bindNull(1)
@@ -151,7 +151,7 @@
}
_result = MyEntity(_tmpInt,_tmpShort,_tmpByte,_tmpLong,_tmpChar,_tmpFloat,_tmpDouble)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt
index 213539a..982d042 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_string.kt
@@ -25,10 +25,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`string`,`nullableString`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindString(1, entity.string)
val _tmpNullableString: String? = entity.nullableString
if (_tmpNullableString == null) {
@@ -71,7 +71,7 @@
}
_result = MyEntity(_tmpString,_tmpNullableString)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt
index a4770df..27d03c4 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_uuid.kt
@@ -28,10 +28,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`uuid`,`nullableUuid`) VALUES (?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindBlob(2, convertUUIDToByte(entity.uuid))
val _tmpNullableUuid: UUID? = entity.nullableUuid
@@ -78,7 +78,7 @@
}
_result = MyEntity(_tmpPk,_tmpUuid,_tmpNullableUuid)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt
index 6ea9026..51844206 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_valueClassConverter.kt
@@ -29,15 +29,17 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`uuidData`,`nullableUuidData`,`nullableLongData`,`doubleNullableLongData`,`genericData`) VALUES (?,?,?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
val _data: Long = checkNotNull(entity.pk.data) {
- "Cannot bind nullable value of inline class to a NOT NULL column." }
+ "Cannot bind NULLABLE value 'data' of inline class 'LongValueClass' to a NOT NULL column."
+ }
statement.bindLong(1, _data)
val _data_1: UUID = checkNotNull(entity.uuidData.data) {
- "Cannot bind nullable value of inline class to a NOT NULL column." }
+ "Cannot bind NULLABLE value 'data' of inline class 'UUIDValueClass' to a NOT NULL column."
+ }
statement.bindBlob(2, convertUUIDToByte(_data_1))
val _tmpNullableUuidData: UUIDValueClass? = entity.nullableUuidData
val _data_2: UUID? = _tmpNullableUuidData?.data
@@ -47,7 +49,8 @@
statement.bindBlob(3, convertUUIDToByte(_data_2))
}
val _data_3: Long = checkNotNull(entity.nullableLongData.data) {
- "Cannot bind nullable value of inline class to a NOT NULL column." }
+ "Cannot bind NULLABLE value 'data' of inline class 'NullableLongValueClass' to a NOT NULL column."
+ }
statement.bindLong(4, _data_3)
val _tmpDoubleNullableLongData: NullableLongValueClass? = entity.doubleNullableLongData
val _data_4: Long? = _tmpDoubleNullableLongData?.data
@@ -57,7 +60,8 @@
statement.bindLong(5, _data_4)
}
val _password: String = checkNotNull(entity.genericData.password) {
- "Cannot bind nullable value of inline class to a NOT NULL column." }
+ "Cannot bind NULLABLE value 'password' of inline class 'GenericValueClass<String>' to a NOT NULL column."
+ }
statement.bindString(6, _password)
}
}
@@ -124,7 +128,7 @@
_result =
MyEntity(_tmpPk,_tmpUuidData,_tmpNullableUuidData,_tmpNullableLongData,_tmpDoubleNullableLongData,_tmpGenericData)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt
index 6276d06..ef617b5 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty.kt
@@ -25,10 +25,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`variablePrimitive`,`variableString`,`variableNullableString`) VALUES (?,?,?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindLong(2, entity.variablePrimitive)
statement.bindString(3, entity.variableString)
@@ -77,7 +77,7 @@
_result.variableNullableString = _cursor.getString(_cursorIndexOfVariableNullableString)
}
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt
index 127eb24..a2eb766 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/pojoRowAdapter_variableProperty_java.kt
@@ -26,10 +26,10 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`mValue`,`mNullableValue`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.getValue())
val _tmpMNullableValue: String? = entity.getNullableValue()
if (_tmpMNullableValue == null) {
@@ -74,7 +74,7 @@
}
_result.setNullableValue(_tmpMNullableValue)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt
index 43a58d3..7e67d4e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_guavaImmutableMap.kt
@@ -43,7 +43,7 @@
_tmpArtistKey = _cursor.getString(_cursorIndexOfArtistKey)
_key = Song(_tmpSongId,_tmpArtistKey)
if (_cursor.isNull(_cursorIndexOfArtistId)) {
- error("Missing value for a key.")
+ error("The column(s) of the map value object of type 'Artist' are NULL but the map's value type argument expect it to be NON-NULL")
}
val _value: Artist
val _tmpArtistId: String
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt
index f42651e..6f80a49 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map.kt
@@ -45,7 +45,7 @@
_tmpArtistKey = _cursor.getString(_cursorIndexOfArtistKey)
_key = Song(_tmpSongId,_tmpArtistKey)
if (_cursor.isNull(_cursorIndexOfArtistId)) {
- error("Missing value for a key.")
+ error("The column(s) of the map value object of type 'Artist' are NULL but the map's value type argument expect it to be NON-NULL")
}
val _value: Artist
val _tmpArtistId: String
@@ -119,7 +119,7 @@
_tmpArtistId = _cursor.getString(_cursorIndexOfArtistId)
_key = Artist(_tmpArtistId)
if (_cursor.isNull(_columnIndexOfSongCount)) {
- error("Missing value for a key.")
+ error("The column(s) of the map value object of type 'Int' are NULL but the map's value type argument expect it to be NON-NULL")
}
val _value: Int
val _tmp: Int
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt
index 1c0720a..1f33090 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/queryResultAdapter_map_ambiguousIndexAdapter.kt
@@ -174,7 +174,7 @@
}
val _tmpName: String
if (_cursorIndexOfName == -1) {
- error("Missing column 'name' for a non null value.")
+ error("Missing value for a NON-NULL column 'name', found NULL value instead.")
} else {
_tmpName = cursor.getString(_cursorIndexOfName)
}
@@ -201,7 +201,7 @@
}
val _tmpText: String
if (_cursorIndexOfText == -1) {
- error("Missing column 'text' for a non null value.")
+ error("Missing value for a NON-NULL column 'text', found NULL value instead.")
} else {
_tmpText = cursor.getString(_cursorIndexOfText)
}
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
index 63a7af9..2361e59 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/rawQuery.kt
@@ -29,7 +29,7 @@
if (_cursor.moveToFirst()) {
_result = __entityCursorConverter_MyEntity(_cursor)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <MyEntity>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
index cf8c543..dee390f 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations.kt
@@ -60,11 +60,11 @@
_tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
_tmpArtist = _collectionArtist.get(_tmpKey_1)
if (_tmpArtist == null) {
- error("Missing relationship item.")
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
}
_result = SongWithArtist(_tmpSong,_tmpArtist)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
}
return _result
} finally {
@@ -102,7 +102,7 @@
_tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
_result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
}
return _result
} finally {
@@ -140,7 +140,7 @@
_tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
_result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
index 7d2189f..a62f18e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_arrayMap.kt
@@ -60,11 +60,11 @@
_tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
_tmpArtist = _collectionArtist.get(_tmpKey_1)
if (_tmpArtist == null) {
- error("Missing relationship item.")
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
}
_result = SongWithArtist(_tmpSong,_tmpArtist)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
}
return _result
} finally {
@@ -102,7 +102,7 @@
_tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
_result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
}
return _result
} finally {
@@ -140,7 +140,7 @@
_tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
_result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
index c8e642f..56c0b4e 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_byteBufferKey.kt
@@ -61,11 +61,11 @@
_tmpKey_1 = ByteBuffer.wrap(_cursor.getBlob(_cursorIndexOfArtistKey))
_tmpArtist = _collectionArtist.get(_tmpKey_1)
if (_tmpArtist == null) {
- error("Missing relationship item.")
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
}
_result = SongWithArtist(_tmpSong,_tmpArtist)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
index 0a73c03..7a48aed 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_longSparseArray.kt
@@ -59,11 +59,11 @@
_tmpKey_1 = _cursor.getLong(_cursorIndexOfArtistKey)
_tmpArtist = _collectionArtist.get(_tmpKey_1)
if (_tmpArtist == null) {
- error("Missing relationship item.")
+ error("Relationship item 'artist' was expected to be NON-NULL but is NULL in @Relation involving a parent column named 'artistKey' and entityColumn named 'artistId'.")
}
_result = SongWithArtist(_tmpSong,_tmpArtist)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
}
return _result
} finally {
@@ -101,7 +101,7 @@
_tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
_result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
}
return _result
} finally {
@@ -139,7 +139,7 @@
_tmpSongsCollection = checkNotNull(_collectionSongs.get(_tmpKey_1))
_result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
index 4618226..9cb1cc6 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/relations_nullable.kt
@@ -79,7 +79,7 @@
}
_result = SongWithArtist(_tmpSong,_tmpArtist)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <SongWithArtist>.")
}
return _result
} finally {
@@ -117,7 +117,7 @@
_tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
_result = ArtistAndSongs(_tmpArtist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <ArtistAndSongs>.")
}
return _result
} finally {
@@ -155,7 +155,7 @@
_tmpSongsCollection = _collectionSongs.getValue(_tmpKey_1)
_result = PlaylistAndSongs(_tmpPlaylist,_tmpSongsCollection)
} else {
- error("Cursor was empty, but expected a single item.")
+ error("The query result was empty, but expected a single row to return a NON-NULL object of type <PlaylistAndSongs>.")
}
return _result
} finally {
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt
index dd1a9ca..94244ec 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx2.kt
@@ -33,26 +33,26 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}
this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+ protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
}
}
this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
@@ -60,18 +60,18 @@
}
this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt
index bbab573..1e0ae5b 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_rx3.kt
@@ -33,26 +33,26 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}
this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+ protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
}
}
this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
@@ -60,18 +60,18 @@
}
this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
diff --git a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt
index 3658985..8c4ef1a 100644
--- a/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt
+++ b/room/room-compiler/src/test/test-data/kotlinCodeGen/shortcutMethods_suspend.kt
@@ -31,26 +31,26 @@
init {
this.__db = __db
this.__insertionAdapterOfMyEntity = object : EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT OR ABORT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}
this.__deletionAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
+ protected override fun createQuery(): String = "DELETE FROM `MyEntity` WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
}
}
this.__updateAdapterOfMyEntity = object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE OR ABORT `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
@@ -58,18 +58,18 @@
}
this.__upsertionAdapterOfMyEntity = EntityUpsertionAdapter<MyEntity>(object :
EntityInsertionAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"INSERT INTO `MyEntity` (`pk`,`other`) VALUES (?,?)"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
}
}, object : EntityDeletionOrUpdateAdapter<MyEntity>(__db) {
- public override fun createQuery(): String =
+ protected override fun createQuery(): String =
"UPDATE `MyEntity` SET `pk` = ?,`other` = ? WHERE `pk` = ?"
- public override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
+ protected override fun bind(statement: SupportSQLiteStatement, entity: MyEntity) {
statement.bindLong(1, entity.pk.toLong())
statement.bindString(2, entity.other)
statement.bindLong(3, entity.pk.toLong())
diff --git a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java
index 1c4ecff..94676b4 100644
--- a/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java
+++ b/samples/MediaRoutingDemo/src/main/java/com/example/androidx/mediarouting/RoutesManager.java
@@ -317,7 +317,7 @@
.setItems(items)
.setLinkedItemComponentName(
new ComponentName(mContext, MainActivity.class))
- .setUseSystemOrdering(mRouteListingSystemOrderingPreferred)
+ .setSystemOrderingEnabled(mRouteListingSystemOrderingPreferred)
.build();
}
mMediaRouter.setRouteListingPreference(routeListingPreference);
diff --git a/settings.gradle b/settings.gradle
index ae52660..3e45fdd 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -26,9 +26,11 @@
repos.addMavenRepositories(repositories)
dependencies {
- classpath("com.gradle:gradle-enterprise-gradle-plugin:3.13")
- classpath("com.gradle:common-custom-user-data-gradle-plugin:1.10")
- classpath("androidx.build.gradle.gcpbuildcache:gcpbuildcache:1.0.0-beta01")
+ // upgrade okio for gcpbuildcache that is compatible with the wire plugin used by androidx
+ classpath("com.squareup.okio:okio:3.3.0")
+ classpath("com.gradle:gradle-enterprise-gradle-plugin:3.14.1")
+ classpath("com.gradle:common-custom-user-data-gradle-plugin:1.11.1")
+ classpath("androidx.build.gradle.gcpbuildcache:gcpbuildcache:1.0.0-beta04")
}
}
@@ -115,6 +117,9 @@
remote(GcpBuildCache) {
projectId = "androidx-ge"
bucketName = "androidx-gradle-remote-cache"
+ messageOnAuthenticationFailure = "Your GCP Credentials have expired.\n" +
+ "Please regenerate credentials following the steps below and try again:\n" +
+ "gcloud auth application-default login --project androidx-ge"
push = (BUILD_NUMBER != null && !BUILD_NUMBER.startsWith("P"))
}
}
@@ -685,6 +690,7 @@
includeProject(":core:core-location-altitude", [BuildType.MAIN])
includeProject(":core:core-location-altitude-proto", [BuildType.MAIN])
includeProject(":core:core-performance", [BuildType.MAIN])
+includeProject(":core:core-performance:integration-tests:testapp", [BuildType.MAIN])
includeProject(":core:core-performance-testing", [BuildType.MAIN])
includeProject(":core:core-performance-play-services", [BuildType.MAIN])
includeProject(":core:core-performance:core-performance-samples", "core/core-performance/samples", [BuildType.MAIN])
@@ -901,6 +907,7 @@
includeProject(":privacysandbox:plugins:plugins-privacysandbox-library", [BuildType.MAIN])
includeProject(":privacysandbox:sdkruntime:sdkruntime-client", [BuildType.MAIN])
includeProject(":privacysandbox:sdkruntime:sdkruntime-core", [BuildType.MAIN])
+includeProject(":privacysandbox:sdkruntime:test-sdks:current", [BuildType.MAIN])
includeProject(":privacysandbox:tools:tools", [BuildType.MAIN])
includeProject(":privacysandbox:tools:tools-apicompiler", [BuildType.MAIN])
includeProject(":privacysandbox:tools:tools-apigenerator", [BuildType.MAIN])
diff --git a/slice/slice-core/src/main/res/values-pt-rPT/strings.xml b/slice/slice-core/src/main/res/values-pt-rPT/strings.xml
index 386b837..0b23942 100644
--- a/slice/slice-core/src/main/res/values-pt-rPT/strings.xml
+++ b/slice/slice-core/src/main/res/values-pt-rPT/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="abc_slices_permission_request" msgid="4431189529265983653">"A app <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
+ <string name="abc_slices_permission_request" msgid="4431189529265983653">"A app <xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="abc_slice_permission_title" msgid="4776010267128891014">"Permitir que a app <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="abc_slice_permission_text_1" msgid="9108592981418900836">"- Pode ler informações da app <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="abc_slice_permission_text_2" msgid="7135705417979137589">"- Pode realizar ações na app <xliff:g id="APP">%1$s</xliff:g>"</string>
diff --git a/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt b/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
index 0bc25f4..01a897c 100644
--- a/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
+++ b/testutils/testutils-macrobenchmark/src/main/java/androidx/testutils/MacrobenchUtils.kt
@@ -25,6 +25,7 @@
import androidx.benchmark.macro.Metric
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupTimingMetric
+import androidx.benchmark.macro.TraceSectionMetric
import androidx.benchmark.macro.isSupportedWithVmSettings
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
@@ -67,7 +68,11 @@
*/
@OptIn(ExperimentalMetricApi::class)
fun getStartupMetrics() =
- listOf(StartupTimingMetric(), MemoryUsageMetric(MemoryUsageMetric.Mode.Last))
+ listOf(
+ StartupTimingMetric(),
+ TraceSectionMetric("StartupTracingInitializer"),
+ MemoryUsageMetric(MemoryUsageMetric.Mode.Last)
+ )
fun MacrobenchmarkRule.measureStartup(
compilationMode: CompilationMode,
diff --git a/tracing/tracing-perfetto/src/main/AndroidManifest.xml b/tracing/tracing-perfetto/src/main/AndroidManifest.xml
index 7402b3a..c955790 100644
--- a/tracing/tracing-perfetto/src/main/AndroidManifest.xml
+++ b/tracing/tracing-perfetto/src/main/AndroidManifest.xml
@@ -32,8 +32,6 @@
</intent-filter>
</receiver>
- <!-- TODO(283953019): enable when feature complete (i.e. after measuring perf impact) -->
- <!--
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
@@ -43,6 +41,12 @@
android:name="androidx.tracing.perfetto.StartupTracingInitializer"
android:value="androidx.startup" />
</provider>
- -->
+ <receiver
+ android:name="androidx.tracing.perfetto.StartupTracingConfigStoreIsEnabledGate"
+ android:enabled="false"
+ android:exported="false"
+ android:directBootAware="false"
+ tools:targetApi="n">
+ </receiver>
</application>
</manifest>
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt
index e83611c..fd34d99 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingConfig.kt
@@ -16,10 +16,13 @@
package androidx.tracing.perfetto
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
import java.io.File
-import java.io.Writer
import java.util.Properties
/**
@@ -28,10 +31,39 @@
* @param libFilePath Path to the optionally sideloaded `libtracing_perfetto.so` file
* @param isPersistent Determines whether tracing should remain enabled (sticky) between app runs
*/
-@RestrictTo(LIBRARY_GROUP)
internal data class StartupTracingConfig(val libFilePath: String?, val isPersistent: Boolean)
-@RestrictTo(LIBRARY_GROUP)
+/**
+ * Hack used by [StartupTracingConfigStore] to perform a fast check whether there is
+ * a [StartupTracingConfig] present. Relies on [PackageManager.getComponentEnabledSetting] and a
+ * dummy [BroadcastReceiver] component.
+ */
+private abstract class StartupTracingConfigStoreIsEnabledGate : BroadcastReceiver() {
+ companion object {
+ fun enable(context: Context) = setEnabledSetting(context, true)
+
+ fun disable(context: Context) = setEnabledSetting(context, false)
+
+ private fun setEnabledSetting(context: Context, enabled: Boolean) {
+ context.packageManager.setComponentEnabledSetting(
+ context.componentName,
+ if (enabled) COMPONENT_ENABLED_STATE_ENABLED else COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP
+ )
+ }
+
+ fun isEnabled(context: Context): Boolean =
+ context.packageManager.getComponentEnabledSetting(context.componentName) ==
+ COMPONENT_ENABLED_STATE_ENABLED
+
+ private val Context.componentName
+ get() = ComponentName(
+ this,
+ StartupTracingConfigStoreIsEnabledGate::class.java.name
+ )
+ }
+}
+
internal object StartupTracingConfigStore {
private const val KEY_IS_PERSISTENT = "isPersistent"
private const val KEY_LIB_FILE_PATH = "libtracingPerfettoFilePath"
@@ -41,9 +73,12 @@
File("/sdcard/Android/media/$packageName/$STARTUP_CONFIG_FILE_NAME")
/** Loads the config */
- fun load(packageName: String): StartupTracingConfig? {
+ fun load(context: Context): StartupTracingConfig? {
+ // use the fast-check-gate value
+ if (!StartupTracingConfigStoreIsEnabledGate.isEnabled(context)) return null
+
// read the config from file
- val propertiesFile = startupConfigFileForPackageName(packageName)
+ val propertiesFile = startupConfigFileForPackageName(context.packageName)
if (!propertiesFile.exists()) return null
val properties = Properties()
propertiesFile.reader().use { properties.load(it) }
@@ -54,24 +89,21 @@
}
/** Stores the config */
- fun StartupTracingConfig.store(packageName: String): Unit =
- startupConfigFileForPackageName(packageName)
+ fun StartupTracingConfig.store(context: Context) {
+ startupConfigFileForPackageName(context.packageName)
.bufferedWriter()
- .use { store(it) }
-
- /**
- * Stores the config as a [Properties] string
- *
- * The caller is responsible for closing the passed-in [Writer]
- */
- private fun StartupTracingConfig.store(writer: Writer) =
- Properties().also {
- it.setProperty(KEY_LIB_FILE_PATH, libFilePath)
- it.setProperty(KEY_IS_PERSISTENT, isPersistent.toString())
- }.store(writer, null)
+ .use { writer ->
+ Properties().also {
+ it.setProperty(KEY_LIB_FILE_PATH, libFilePath)
+ it.setProperty(KEY_IS_PERSISTENT, isPersistent.toString())
+ }.store(writer, null)
+ }
+ StartupTracingConfigStoreIsEnabledGate.enable(context) // update the fast-check-gate value
+ }
/** Deletes the config */
- fun clear(packageName: String) {
- startupConfigFileForPackageName(packageName).delete()
+ fun clear(context: Context) {
+ StartupTracingConfigStoreIsEnabledGate.disable(context) // update the fast-check-gate value
+ startupConfigFileForPackageName(context.packageName).delete()
}
}
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt
index ab2d6fd..ee2ea0d 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/StartupTracingInitializer.kt
@@ -18,6 +18,7 @@
import android.content.Context
import android.os.Build
+import android.os.StrictMode
import android.util.Log
import androidx.startup.Initializer
import androidx.tracing.perfetto.internal.handshake.protocol.Response
@@ -33,27 +34,38 @@
// TODO(234351579): Support API < 30
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return
- // read startup tracing config file if present
- val packageName = context.applicationInfo.packageName
- val config = StartupTracingConfigStore.load(packageName)
- ?: return // early exit if no config is found
+ suppressStrictModeDiskWrites {
+ // read startup tracing config if present
+ val config = StartupTracingConfigStore.load(context)
+ ?: return // early exit if no config is found
- // delete config file if not meant to be preserved between runs
- if (!config.isPersistent) StartupTracingConfigStore.clear(packageName)
+ // delete config if not meant to be preserved between runs
+ if (!config.isPersistent) StartupTracingConfigStore.clear(context)
- // enable tracing
- val libFilePath = config.libFilePath
- val enableTracingResponse =
- if (libFilePath == null) PerfettoSdkTrace.enable()
- else PerfettoSdkTrace.enable(File(libFilePath), context)
+ // enable tracing
+ val libFilePath = config.libFilePath
+ val enableTracingResponse =
+ if (libFilePath == null) PerfettoSdkTrace.enable()
+ else PerfettoSdkTrace.enable(File(libFilePath), context)
- // log the result for debuggability
- Log.d(TAG, "${Response::class.java.name}: { " +
- "resultCode: ${enableTracingResponse.resultCode}, " +
- "message: ${enableTracingResponse.message}, " +
- "requiredVersion: ${enableTracingResponse.requiredVersion} " +
- "}")
+ // log the result for debuggability
+ Log.d(TAG, "${Response::class.java.name}: { " +
+ "resultCode: ${enableTracingResponse.resultCode}, " +
+ "message: ${enableTracingResponse.message}, " +
+ "requiredVersion: ${enableTracingResponse.requiredVersion} " +
+ "}")
+ }
}
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
+
+ // TODO(245426369): test in TrivialStartupTracingBenchmark
+ private inline fun <R> suppressStrictModeDiskWrites(block: () -> R): R {
+ val oldPolicy = StrictMode.allowThreadDiskWrites()
+ try {
+ return block()
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy)
+ }
+ }
}
diff --git a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
index 2bfa12e..6f45b92 100644
--- a/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
+++ b/tracing/tracing-perfetto/src/main/java/androidx/tracing/perfetto/TracingReceiver.kt
@@ -134,13 +134,13 @@
RESULT_CODE_ERROR_OTHER,
"Cannot set up cold start tracing without a Context instance."
)
- config.store(context.applicationInfo.packageName)
+ config.store(context)
}
}
private fun disableTracingColdStart(context: Context?): Response = when {
context != null -> {
- StartupTracingConfigStore.clear(context.applicationInfo.packageName)
+ StartupTracingConfigStore.clear(context)
Response(RESULT_CODE_SUCCESS)
}
else ->
diff --git a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt
index 03ae1e9..472ba2f 100644
--- a/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt
+++ b/tv/integration-tests/playground/src/main/java/androidx/tv/integration/playground/TextField.kt
@@ -25,8 +25,8 @@
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
-import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
@@ -38,6 +38,9 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
+import androidx.tv.foundation.ExperimentalTvFoundationApi
+import androidx.tv.foundation.text.AndroidImeOptions
+import androidx.tv.foundation.text.TvKeyboardAlignment
@Composable
fun TextFieldContent() {
@@ -62,7 +65,7 @@
}
}
-@OptIn(ExperimentalMaterial3Api::class)
+@OptIn(ExperimentalTvFoundationApi::class)
@Composable
fun SampleTextField(label: String) {
var text by remember { mutableStateOf("") }
@@ -77,6 +80,9 @@
placeholder = {
Text("$label...")
},
+ keyboardOptions = KeyboardOptions(
+ platformImeOptions = AndroidImeOptions(TvKeyboardAlignment.Left)
+ ),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Color.Cyan,
focusedLabelColor = Color.Cyan,
diff --git a/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt b/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt
index 345adc6..dc061ec 100644
--- a/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt
+++ b/tv/samples/src/main/java/androidx/tv/samples/NavigationDrawerSamples.kt
@@ -32,6 +32,7 @@
import androidx.compose.material3.Button
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -80,7 +81,7 @@
@OptIn(ExperimentalTvMaterial3Api::class)
@Sampled
@Composable
-fun SampleModalNavigationDrawer() {
+fun SampleModalNavigationDrawerWithSolidScrim() {
val navigationRow: @Composable (drawerValue: DrawerValue, color: Color, text: String) -> Unit =
{ drawerValue, color, text ->
Row(Modifier.padding(10.dp).focusable()) {
@@ -112,3 +113,40 @@
}
}
}
+
+@OptIn(ExperimentalTvMaterial3Api::class)
+@Sampled
+@Composable
+fun SampleModalNavigationDrawerWithGradientScrim() {
+ val navigationRow: @Composable (drawerValue: DrawerValue, color: Color, text: String) -> Unit =
+ { drawerValue, color, text ->
+ Row(Modifier.padding(10.dp).focusable()) {
+ Box(Modifier.size(50.dp).background(color).padding(end = 20.dp))
+ AnimatedVisibility(visible = drawerValue == DrawerValue.Open) {
+ Text(
+ text = text,
+ softWrap = false,
+ modifier = Modifier.padding(15.dp).width(50.dp),
+ textAlign = TextAlign.Center
+ )
+ }
+ }
+ }
+
+ androidx.tv.material3.ModalNavigationDrawer(
+ drawerContent = {
+ Column(Modifier.fillMaxHeight()) {
+ navigationRow(it, Color.Red, "Red")
+ navigationRow(it, Color.Blue, "Blue")
+ navigationRow(it, Color.Yellow, "Yellow")
+ }
+ },
+ scrimBrush = Brush.horizontalGradient(listOf(Color.DarkGray, Color.Transparent))
+ ) {
+ Button(modifier = Modifier
+ .height(100.dp)
+ .fillMaxWidth(), onClick = {}) {
+ Text("BUTTON")
+ }
+ }
+}
diff --git a/tv/tv-foundation/api/current.txt b/tv/tv-foundation/api/current.txt
index 968ee57..d8098f2 100644
--- a/tv/tv-foundation/api/current.txt
+++ b/tv/tv-foundation/api/current.txt
@@ -242,3 +242,23 @@
}
+package androidx.tv.foundation.text {
+
+ public final class TvImeOptionsKt {
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions AndroidImeOptions(androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions keyboardAlignment(androidx.compose.ui.text.input.AndroidImeOptions, androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ }
+
+ @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public enum TvKeyboardAlignment {
+ method public final String! getOption();
+ method public static androidx.tv.foundation.text.TvKeyboardAlignment valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.tv.foundation.text.TvKeyboardAlignment[] values();
+ property public final String! option;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Center;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Fullscreen;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Left;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Right;
+ }
+
+}
+
diff --git a/tv/tv-foundation/api/restricted_current.txt b/tv/tv-foundation/api/restricted_current.txt
index 968ee57..d8098f2 100644
--- a/tv/tv-foundation/api/restricted_current.txt
+++ b/tv/tv-foundation/api/restricted_current.txt
@@ -242,3 +242,23 @@
}
+package androidx.tv.foundation.text {
+
+ public final class TvImeOptionsKt {
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions AndroidImeOptions(androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ method @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public static androidx.compose.ui.text.input.AndroidImeOptions keyboardAlignment(androidx.compose.ui.text.input.AndroidImeOptions, androidx.tv.foundation.text.TvKeyboardAlignment horizontalAlignment);
+ }
+
+ @SuppressCompatibility @androidx.tv.foundation.ExperimentalTvFoundationApi public enum TvKeyboardAlignment {
+ method public final String! getOption();
+ method public static androidx.tv.foundation.text.TvKeyboardAlignment valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+ method public static androidx.tv.foundation.text.TvKeyboardAlignment[] values();
+ property public final String! option;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Center;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Fullscreen;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Left;
+ enum_constant public static final androidx.tv.foundation.text.TvKeyboardAlignment Right;
+ }
+
+}
+
diff --git a/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/text/TvImeOptionsTest.kt b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/text/TvImeOptionsTest.kt
new file mode 100644
index 0000000..7a29001
--- /dev/null
+++ b/tv/tv-foundation/src/androidTest/java/androidx/tv/foundation/text/TvImeOptionsTest.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.foundation.text
+
+import androidx.compose.ui.text.input.AndroidImeOptions
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.tv.foundation.ExperimentalTvFoundationApi
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalTvFoundationApi::class)
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class TvImeOptionsTest {
+ @Test
+ fun privateImeOptions_keyboardAlignment() {
+ val privateImeOptions = "testOptions"
+ val keyboardAlignment = TvKeyboardAlignment.Left
+ val imeOptions = AndroidImeOptions(privateImeOptions).keyboardAlignment(keyboardAlignment)
+
+ assertThat(
+ imeOptions.privateImeOptions == "$privateImeOptions,${keyboardAlignment.option}"
+ ).isTrue()
+ }
+}
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
index b95b687..5cf5964 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/grid/LazyGrid.kt
@@ -127,7 +127,7 @@
),
prefetchState = state.prefetchState,
measurePolicy = measurePolicy,
- itemProvider = itemProvider
+ itemProvider = { itemProvider }
)
}
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
index 224af43..34254cc 100644
--- a/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/lazy/list/LazyList.kt
@@ -131,7 +131,7 @@
),
prefetchState = state.prefetchState,
measurePolicy = measurePolicy,
- itemProvider = itemProvider
+ itemProvider = { itemProvider }
)
}
diff --git a/tv/tv-foundation/src/main/java/androidx/tv/foundation/text/TvImeOptions.kt b/tv/tv-foundation/src/main/java/androidx/tv/foundation/text/TvImeOptions.kt
new file mode 100644
index 0000000..135534a
--- /dev/null
+++ b/tv/tv-foundation/src/main/java/androidx/tv/foundation/text/TvImeOptions.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.tv.foundation.text
+
+import androidx.compose.ui.text.input.AndroidImeOptions
+import androidx.tv.foundation.ExperimentalTvFoundationApi
+
+/**
+ * Additional IME configuration options supported for TV.
+ *
+ * It is not guaranteed if IME will comply with the options provided here.
+ *
+ * @param horizontalAlignment defines the horizontal alignment [TvKeyboardAlignment] option for
+ * keyboard.
+ */
+@ExperimentalTvFoundationApi
+fun AndroidImeOptions(
+ horizontalAlignment: TvKeyboardAlignment
+) = AndroidImeOptions(horizontalAlignment.option)
+
+/**
+ * Adds the keyboard alignment option to the private IME configuration options.
+ *
+ * It is not guaranteed if IME will comply with the options provided here.
+ *
+ * @param horizontalAlignment defines the horizontal alignment [TvKeyboardAlignment] option for
+ * keyboard.
+ */
+@ExperimentalTvFoundationApi
+fun AndroidImeOptions.keyboardAlignment(
+ horizontalAlignment: TvKeyboardAlignment
+): AndroidImeOptions {
+ val privateImeOptions =
+ if (!privateImeOptions.isNullOrBlank()) this.privateImeOptions + "," else ""
+ return AndroidImeOptions(privateImeOptions + horizontalAlignment.option)
+}
+
+/**
+ * Represents the TV keyboard alignment options available for TextField(s).
+ *
+ * It is not guaranteed if IME will comply with the options provided here.
+ */
+@ExperimentalTvFoundationApi
+enum class TvKeyboardAlignment(val option: String? = null) {
+ Left("horizontalAlignment=left"),
+ Right("horizontalAlignment=right"),
+ Center("horizontalAlignment=center"),
+ Fullscreen("fullWidthKeyboard")
+}
diff --git a/tv/tv-material/api/current.txt b/tv/tv-material/api/current.txt
index 1c964b9..3dca4bb 100644
--- a/tv/tv-material/api/current.txt
+++ b/tv/tv-material/api/current.txt
@@ -425,35 +425,116 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemBorder {
+ ctor public ListItemBorder(androidx.tv.material3.Border border, androidx.tv.material3.Border focusedBorder, androidx.tv.material3.Border pressedBorder, androidx.tv.material3.Border selectedBorder, androidx.tv.material3.Border disabledBorder, androidx.tv.material3.Border focusedSelectedBorder, androidx.tv.material3.Border focusedDisabledBorder, androidx.tv.material3.Border pressedSelectedBorder);
+ method public androidx.tv.material3.Border getBorder();
+ method public androidx.tv.material3.Border getDisabledBorder();
+ method public androidx.tv.material3.Border getFocusedBorder();
+ method public androidx.tv.material3.Border getFocusedDisabledBorder();
+ method public androidx.tv.material3.Border getFocusedSelectedBorder();
+ method public androidx.tv.material3.Border getPressedBorder();
+ method public androidx.tv.material3.Border getPressedSelectedBorder();
+ method public androidx.tv.material3.Border getSelectedBorder();
+ property public final androidx.tv.material3.Border border;
+ property public final androidx.tv.material3.Border disabledBorder;
+ property public final androidx.tv.material3.Border focusedBorder;
+ property public final androidx.tv.material3.Border focusedDisabledBorder;
+ property public final androidx.tv.material3.Border focusedSelectedBorder;
+ property public final androidx.tv.material3.Border pressedBorder;
+ property public final androidx.tv.material3.Border pressedSelectedBorder;
+ property public final androidx.tv.material3.Border selectedBorder;
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemColors {
+ ctor public ListItemColors(long containerColor, long contentColor, long focusedContainerColor, long focusedContentColor, long pressedContainerColor, long pressedContentColor, long selectedContainerColor, long selectedContentColor, long disabledContainerColor, long disabledContentColor, long focusedSelectedContainerColor, long focusedSelectedContentColor, long pressedSelectedContainerColor, long pressedSelectedContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ method public long getFocusedContainerColor();
+ method public long getFocusedContentColor();
+ method public long getFocusedSelectedContainerColor();
+ method public long getFocusedSelectedContentColor();
+ method public long getPressedContainerColor();
+ method public long getPressedContentColor();
+ method public long getPressedSelectedContainerColor();
+ method public long getPressedSelectedContentColor();
+ method public long getSelectedContainerColor();
+ method public long getSelectedContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ property public final long focusedContainerColor;
+ property public final long focusedContentColor;
+ property public final long focusedSelectedContainerColor;
+ property public final long focusedSelectedContentColor;
+ property public final long pressedContainerColor;
+ property public final long pressedContentColor;
+ property public final long pressedSelectedContainerColor;
+ property public final long pressedSelectedContentColor;
+ property public final long selectedContainerColor;
+ property public final long selectedContentColor;
}
@SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemDefaults {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.Border getFocusedDisabledBorder();
method public float getIconSize();
method public float getIconSizeDense();
method public float getListItemElevation();
+ method public androidx.compose.foundation.shape.RoundedCornerShape getListItemShape();
method public androidx.tv.material3.ListItemGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
method public androidx.tv.material3.ListItemScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale);
method public androidx.tv.material3.ListItemShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape);
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.tv.material3.Border FocusedDisabledBorder;
property public final float IconSize;
property public final float IconSizeDense;
property public final float ListItemElevation;
+ property public final androidx.compose.foundation.shape.RoundedCornerShape ListItemShape;
field public static final androidx.tv.material3.ListItemDefaults INSTANCE;
+ field public static final float SelectedContinerColorOpacity = 0.4f;
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemGlow {
+ ctor public ListItemGlow(androidx.tv.material3.Glow glow, androidx.tv.material3.Glow focusedGlow, androidx.tv.material3.Glow pressedGlow, androidx.tv.material3.Glow selectedGlow, androidx.tv.material3.Glow focusedSelectedGlow, androidx.tv.material3.Glow pressedSelectedGlow);
+ method public androidx.tv.material3.Glow getFocusedGlow();
+ method public androidx.tv.material3.Glow getFocusedSelectedGlow();
+ method public androidx.tv.material3.Glow getGlow();
+ method public androidx.tv.material3.Glow getPressedGlow();
+ method public androidx.tv.material3.Glow getPressedSelectedGlow();
+ method public androidx.tv.material3.Glow getSelectedGlow();
+ property public final androidx.tv.material3.Glow focusedGlow;
+ property public final androidx.tv.material3.Glow focusedSelectedGlow;
+ property public final androidx.tv.material3.Glow glow;
+ property public final androidx.tv.material3.Glow pressedGlow;
+ property public final androidx.tv.material3.Glow pressedSelectedGlow;
+ property public final androidx.tv.material3.Glow selectedGlow;
}
public final class ListItemKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void DenseListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void DenseListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent);
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemScale {
+ ctor public ListItemScale(@FloatRange(from=0.0) float scale, @FloatRange(from=0.0) float focusedScale, @FloatRange(from=0.0) float pressedScale, @FloatRange(from=0.0) float selectedScale, @FloatRange(from=0.0) float disabledScale, @FloatRange(from=0.0) float focusedSelectedScale, @FloatRange(from=0.0) float focusedDisabledScale, @FloatRange(from=0.0) float pressedSelectedScale);
+ method public float getDisabledScale();
+ method public float getFocusedDisabledScale();
+ method public float getFocusedScale();
+ method public float getFocusedSelectedScale();
+ method public float getPressedScale();
+ method public float getPressedSelectedScale();
+ method public float getScale();
+ method public float getSelectedScale();
+ property public final float disabledScale;
+ property public final float focusedDisabledScale;
+ property public final float focusedScale;
+ property public final float focusedSelectedScale;
+ property public final float pressedScale;
+ property public final float pressedSelectedScale;
+ property public final float scale;
+ property public final float selectedScale;
field public static final androidx.tv.material3.ListItemScale.Companion Companion;
}
@@ -463,6 +544,23 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemShape {
+ ctor public ListItemShape(androidx.compose.ui.graphics.Shape shape, androidx.compose.ui.graphics.Shape focusedShape, androidx.compose.ui.graphics.Shape pressedShape, androidx.compose.ui.graphics.Shape selectedShape, androidx.compose.ui.graphics.Shape disabledShape, androidx.compose.ui.graphics.Shape focusedSelectedShape, androidx.compose.ui.graphics.Shape focusedDisabledShape, androidx.compose.ui.graphics.Shape pressedSelectedShape);
+ method public androidx.compose.ui.graphics.Shape getDisabledShape();
+ method public androidx.compose.ui.graphics.Shape getFocusedDisabledShape();
+ method public androidx.compose.ui.graphics.Shape getFocusedSelectedShape();
+ method public androidx.compose.ui.graphics.Shape getFocusedShape();
+ method public androidx.compose.ui.graphics.Shape getPressedSelectedShape();
+ method public androidx.compose.ui.graphics.Shape getPressedShape();
+ method public androidx.compose.ui.graphics.Shape getSelectedShape();
+ method public androidx.compose.ui.graphics.Shape getShape();
+ property public final androidx.compose.ui.graphics.Shape disabledShape;
+ property public final androidx.compose.ui.graphics.Shape focusedDisabledShape;
+ property public final androidx.compose.ui.graphics.Shape focusedSelectedShape;
+ property public final androidx.compose.ui.graphics.Shape focusedShape;
+ property public final androidx.compose.ui.graphics.Shape pressedSelectedShape;
+ property public final androidx.compose.ui.graphics.Shape pressedShape;
+ property public final androidx.compose.ui.graphics.Shape selectedShape;
+ property public final androidx.compose.ui.graphics.Shape shape;
}
@SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class MaterialTheme {
@@ -480,7 +578,7 @@
}
public final class NavigationDrawerKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static androidx.tv.material3.DrawerState rememberDrawerState(androidx.tv.material3.DrawerValue initialValue);
}
diff --git a/tv/tv-material/api/restricted_current.txt b/tv/tv-material/api/restricted_current.txt
index 1c964b9..3dca4bb 100644
--- a/tv/tv-material/api/restricted_current.txt
+++ b/tv/tv-material/api/restricted_current.txt
@@ -425,35 +425,116 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemBorder {
+ ctor public ListItemBorder(androidx.tv.material3.Border border, androidx.tv.material3.Border focusedBorder, androidx.tv.material3.Border pressedBorder, androidx.tv.material3.Border selectedBorder, androidx.tv.material3.Border disabledBorder, androidx.tv.material3.Border focusedSelectedBorder, androidx.tv.material3.Border focusedDisabledBorder, androidx.tv.material3.Border pressedSelectedBorder);
+ method public androidx.tv.material3.Border getBorder();
+ method public androidx.tv.material3.Border getDisabledBorder();
+ method public androidx.tv.material3.Border getFocusedBorder();
+ method public androidx.tv.material3.Border getFocusedDisabledBorder();
+ method public androidx.tv.material3.Border getFocusedSelectedBorder();
+ method public androidx.tv.material3.Border getPressedBorder();
+ method public androidx.tv.material3.Border getPressedSelectedBorder();
+ method public androidx.tv.material3.Border getSelectedBorder();
+ property public final androidx.tv.material3.Border border;
+ property public final androidx.tv.material3.Border disabledBorder;
+ property public final androidx.tv.material3.Border focusedBorder;
+ property public final androidx.tv.material3.Border focusedDisabledBorder;
+ property public final androidx.tv.material3.Border focusedSelectedBorder;
+ property public final androidx.tv.material3.Border pressedBorder;
+ property public final androidx.tv.material3.Border pressedSelectedBorder;
+ property public final androidx.tv.material3.Border selectedBorder;
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemColors {
+ ctor public ListItemColors(long containerColor, long contentColor, long focusedContainerColor, long focusedContentColor, long pressedContainerColor, long pressedContentColor, long selectedContainerColor, long selectedContentColor, long disabledContainerColor, long disabledContentColor, long focusedSelectedContainerColor, long focusedSelectedContentColor, long pressedSelectedContainerColor, long pressedSelectedContentColor);
+ method public long getContainerColor();
+ method public long getContentColor();
+ method public long getDisabledContainerColor();
+ method public long getDisabledContentColor();
+ method public long getFocusedContainerColor();
+ method public long getFocusedContentColor();
+ method public long getFocusedSelectedContainerColor();
+ method public long getFocusedSelectedContentColor();
+ method public long getPressedContainerColor();
+ method public long getPressedContentColor();
+ method public long getPressedSelectedContainerColor();
+ method public long getPressedSelectedContentColor();
+ method public long getSelectedContainerColor();
+ method public long getSelectedContentColor();
+ property public final long containerColor;
+ property public final long contentColor;
+ property public final long disabledContainerColor;
+ property public final long disabledContentColor;
+ property public final long focusedContainerColor;
+ property public final long focusedContentColor;
+ property public final long focusedSelectedContainerColor;
+ property public final long focusedSelectedContentColor;
+ property public final long pressedContainerColor;
+ property public final long pressedContentColor;
+ property public final long pressedSelectedContainerColor;
+ property public final long pressedSelectedContentColor;
+ property public final long selectedContainerColor;
+ property public final long selectedContentColor;
}
@SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemDefaults {
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemBorder border(optional androidx.tv.material3.Border border, optional androidx.tv.material3.Border focusedBorder, optional androidx.tv.material3.Border pressedBorder, optional androidx.tv.material3.Border selectedBorder, optional androidx.tv.material3.Border disabledBorder, optional androidx.tv.material3.Border focusedSelectedBorder, optional androidx.tv.material3.Border focusedDisabledBorder, optional androidx.tv.material3.Border pressedSelectedBorder);
method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.ListItemColors colors(optional long containerColor, optional long contentColor, optional long focusedContainerColor, optional long focusedContentColor, optional long pressedContainerColor, optional long pressedContentColor, optional long selectedContainerColor, optional long selectedContentColor, optional long disabledContainerColor, optional long disabledContentColor, optional long focusedSelectedContainerColor, optional long focusedSelectedContentColor, optional long pressedSelectedContainerColor, optional long pressedSelectedContentColor);
+ method @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public androidx.tv.material3.Border getFocusedDisabledBorder();
method public float getIconSize();
method public float getIconSizeDense();
method public float getListItemElevation();
+ method public androidx.compose.foundation.shape.RoundedCornerShape getListItemShape();
method public androidx.tv.material3.ListItemGlow glow(optional androidx.tv.material3.Glow glow, optional androidx.tv.material3.Glow focusedGlow, optional androidx.tv.material3.Glow pressedGlow, optional androidx.tv.material3.Glow selectedGlow, optional androidx.tv.material3.Glow focusedSelectedGlow, optional androidx.tv.material3.Glow pressedSelectedGlow);
method public androidx.tv.material3.ListItemScale scale(optional @FloatRange(from=0.0) float scale, optional @FloatRange(from=0.0) float focusedScale, optional @FloatRange(from=0.0) float pressedScale, optional @FloatRange(from=0.0) float selectedScale, optional @FloatRange(from=0.0) float disabledScale, optional @FloatRange(from=0.0) float focusedSelectedScale, optional @FloatRange(from=0.0) float focusedDisabledScale, optional @FloatRange(from=0.0) float pressedSelectedScale);
method public androidx.tv.material3.ListItemShape shape(optional androidx.compose.ui.graphics.Shape shape, optional androidx.compose.ui.graphics.Shape focusedShape, optional androidx.compose.ui.graphics.Shape pressedShape, optional androidx.compose.ui.graphics.Shape selectedShape, optional androidx.compose.ui.graphics.Shape disabledShape, optional androidx.compose.ui.graphics.Shape focusedSelectedShape, optional androidx.compose.ui.graphics.Shape focusedDisabledShape, optional androidx.compose.ui.graphics.Shape pressedSelectedShape);
+ property @androidx.compose.runtime.Composable @androidx.compose.runtime.ReadOnlyComposable public final androidx.tv.material3.Border FocusedDisabledBorder;
property public final float IconSize;
property public final float IconSizeDense;
property public final float ListItemElevation;
+ property public final androidx.compose.foundation.shape.RoundedCornerShape ListItemShape;
field public static final androidx.tv.material3.ListItemDefaults INSTANCE;
+ field public static final float SelectedContinerColorOpacity = 0.4f;
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemGlow {
+ ctor public ListItemGlow(androidx.tv.material3.Glow glow, androidx.tv.material3.Glow focusedGlow, androidx.tv.material3.Glow pressedGlow, androidx.tv.material3.Glow selectedGlow, androidx.tv.material3.Glow focusedSelectedGlow, androidx.tv.material3.Glow pressedSelectedGlow);
+ method public androidx.tv.material3.Glow getFocusedGlow();
+ method public androidx.tv.material3.Glow getFocusedSelectedGlow();
+ method public androidx.tv.material3.Glow getGlow();
+ method public androidx.tv.material3.Glow getPressedGlow();
+ method public androidx.tv.material3.Glow getPressedSelectedGlow();
+ method public androidx.tv.material3.Glow getSelectedGlow();
+ property public final androidx.tv.material3.Glow focusedGlow;
+ property public final androidx.tv.material3.Glow focusedSelectedGlow;
+ property public final androidx.tv.material3.Glow glow;
+ property public final androidx.tv.material3.Glow pressedGlow;
+ property public final androidx.tv.material3.Glow pressedSelectedGlow;
+ property public final androidx.tv.material3.Glow selectedGlow;
}
public final class ListItemKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void DenseListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void DenseListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ListItem(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional kotlin.jvm.functions.Function0<kotlin.Unit>? onLongClick, optional kotlin.jvm.functions.Function0<kotlin.Unit>? overlineContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? supportingContent, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? leadingContent, optional kotlin.jvm.functions.Function0<kotlin.Unit>? trailingContent, optional float tonalElevation, optional androidx.tv.material3.ListItemShape shape, optional androidx.tv.material3.ListItemColors colors, optional androidx.tv.material3.ListItemScale scale, optional androidx.tv.material3.ListItemBorder border, optional androidx.tv.material3.ListItemGlow glow, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> headlineContent);
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemScale {
+ ctor public ListItemScale(@FloatRange(from=0.0) float scale, @FloatRange(from=0.0) float focusedScale, @FloatRange(from=0.0) float pressedScale, @FloatRange(from=0.0) float selectedScale, @FloatRange(from=0.0) float disabledScale, @FloatRange(from=0.0) float focusedSelectedScale, @FloatRange(from=0.0) float focusedDisabledScale, @FloatRange(from=0.0) float pressedSelectedScale);
+ method public float getDisabledScale();
+ method public float getFocusedDisabledScale();
+ method public float getFocusedScale();
+ method public float getFocusedSelectedScale();
+ method public float getPressedScale();
+ method public float getPressedSelectedScale();
+ method public float getScale();
+ method public float getSelectedScale();
+ property public final float disabledScale;
+ property public final float focusedDisabledScale;
+ property public final float focusedScale;
+ property public final float focusedSelectedScale;
+ property public final float pressedScale;
+ property public final float pressedSelectedScale;
+ property public final float scale;
+ property public final float selectedScale;
field public static final androidx.tv.material3.ListItemScale.Companion Companion;
}
@@ -463,6 +544,23 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.tv.material3.ExperimentalTvMaterial3Api public final class ListItemShape {
+ ctor public ListItemShape(androidx.compose.ui.graphics.Shape shape, androidx.compose.ui.graphics.Shape focusedShape, androidx.compose.ui.graphics.Shape pressedShape, androidx.compose.ui.graphics.Shape selectedShape, androidx.compose.ui.graphics.Shape disabledShape, androidx.compose.ui.graphics.Shape focusedSelectedShape, androidx.compose.ui.graphics.Shape focusedDisabledShape, androidx.compose.ui.graphics.Shape pressedSelectedShape);
+ method public androidx.compose.ui.graphics.Shape getDisabledShape();
+ method public androidx.compose.ui.graphics.Shape getFocusedDisabledShape();
+ method public androidx.compose.ui.graphics.Shape getFocusedSelectedShape();
+ method public androidx.compose.ui.graphics.Shape getFocusedShape();
+ method public androidx.compose.ui.graphics.Shape getPressedSelectedShape();
+ method public androidx.compose.ui.graphics.Shape getPressedShape();
+ method public androidx.compose.ui.graphics.Shape getSelectedShape();
+ method public androidx.compose.ui.graphics.Shape getShape();
+ property public final androidx.compose.ui.graphics.Shape disabledShape;
+ property public final androidx.compose.ui.graphics.Shape focusedDisabledShape;
+ property public final androidx.compose.ui.graphics.Shape focusedSelectedShape;
+ property public final androidx.compose.ui.graphics.Shape focusedShape;
+ property public final androidx.compose.ui.graphics.Shape pressedSelectedShape;
+ property public final androidx.compose.ui.graphics.Shape pressedShape;
+ property public final androidx.compose.ui.graphics.Shape selectedShape;
+ property public final androidx.compose.ui.graphics.Shape shape;
}
@SuppressCompatibility @androidx.tv.material3.ExperimentalTvMaterial3Api public final class MaterialTheme {
@@ -480,7 +578,7 @@
}
public final class NavigationDrawerKt {
- method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional long scrimColor, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void ModalNavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, optional androidx.compose.ui.graphics.Brush scrimBrush, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static void NavigationDrawer(kotlin.jvm.functions.Function1<? super androidx.tv.material3.DrawerValue,kotlin.Unit> drawerContent, optional androidx.compose.ui.Modifier modifier, optional androidx.tv.material3.DrawerState drawerState, kotlin.jvm.functions.Function0<kotlin.Unit> content);
method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.tv.material3.ExperimentalTvMaterial3Api public static androidx.tv.material3.DrawerState rememberDrawerState(androidx.tv.material3.DrawerValue initialValue);
}
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ListItem.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ListItem.kt
index 6e1a4a1..83bea78 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/ListItem.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ListItem.kt
@@ -50,7 +50,6 @@
*
* @param selected defines whether this ListItem is selected or not
* @param onClick called when this ListItem is clicked
- * @param headlineContent the [Composable] headline content of the list item
* @param modifier [Modifier] to be applied to the list item
* @param enabled controls the enabled state of this list item. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
@@ -75,13 +74,13 @@
* [Interaction]s for this component. You can create and pass in your own [remember]ed instance
* to observe [Interaction]s and customize the appearance / behavior of this list item in different
* states.
+ * @param headlineContent the [Composable] headline content of the list item
*/
@ExperimentalTvMaterial3Api
@Composable
fun ListItem(
selected: Boolean,
onClick: () -> Unit,
- headlineContent: @Composable () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
onLongClick: (() -> Unit)? = null,
@@ -95,7 +94,8 @@
scale: ListItemScale = ListItemDefaults.scale(),
border: ListItemBorder = ListItemDefaults.border(),
glow: ListItemGlow = ListItemDefaults.glow(),
- interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ headlineContent: @Composable () -> Unit
) {
BaseListItem(
selected = selected,
@@ -142,7 +142,6 @@
*
* @param selected defines whether this ListItem is selected or not
* @param onClick called when this ListItem is clicked
- * @param headlineContent the [Composable] headline content of the list item
* @param modifier [Modifier] to be applied to the list item
* @param enabled controls the enabled state of this list item. When `false`, this component will
* not respond to user input, and it will appear visually disabled and disabled to accessibility
@@ -167,13 +166,13 @@
* [Interaction]s for this component. You can create and pass in your own [remember]ed instance
* to observe [Interaction]s and customize the appearance / behavior of this list item in different
* states.
+ * @param headlineContent the [Composable] headline content of the list item
*/
@ExperimentalTvMaterial3Api
@Composable
fun DenseListItem(
selected: Boolean,
onClick: () -> Unit,
- headlineContent: @Composable () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
onLongClick: (() -> Unit)? = null,
@@ -187,7 +186,8 @@
scale: ListItemScale = ListItemDefaults.scale(),
border: ListItemBorder = ListItemDefaults.border(),
glow: ListItemGlow = ListItemDefaults.glow(),
- interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ headlineContent: @Composable () -> Unit
) {
BaseListItem(
selected = selected,
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
index 922a83a..5f35ce9 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemDefaults.kt
@@ -49,6 +49,28 @@
val ListItemElevation = Elevation.Level0
/**
+ * The default shape for a [ListItem].
+ */
+ val ListItemShape = RoundedCornerShape(8.dp)
+
+ /**
+ * The default border applied to [ListItem] in focused disabled state.
+ */
+ val FocusedDisabledBorder
+ @ReadOnlyComposable
+ @Composable get() = Border(
+ border = BorderStroke(
+ width = 2.dp,
+ color = MaterialTheme.colorScheme.border
+ )
+ )
+
+ /**
+ * The default opacity for the [ListItem] container color in selected state.
+ */
+ const val SelectedContinerColorOpacity = 0.4f
+
+ /**
* The default content padding [PaddingValues] used by [ListItem]
*/
internal val ContentPadding = PaddingValues(
@@ -63,6 +85,7 @@
horizontal = 12.dp,
vertical = 10.dp
)
+
internal const val LeadingContentOpacity = 0.8f
internal const val OverlineContentOpacity = 0.6f
internal const val SupportingContentOpacity = 0.8f
@@ -80,18 +103,6 @@
internal val MinDenseContainerHeightTwoLine = 56.dp
internal val MinDenseContainerHeightThreeLine = 72.dp
- private val ListItemShape = RoundedCornerShape(8.dp)
-
- private val DefaultBorder
- @ReadOnlyComposable
- @Composable get() = Border(
- border = BorderStroke(
- width = 2.dp,
- color = MaterialTheme.colorScheme.border
- ),
- shape = ListItemShape
- )
-
/**
* Creates a [ListItemShape] that represents the default container shapes used in a ListItem
*
@@ -162,7 +173,7 @@
pressedContainerColor: Color = focusedContainerColor,
pressedContentColor: Color = contentColorFor(focusedContainerColor),
selectedContainerColor: Color = MaterialTheme.colorScheme.secondaryContainer
- .copy(alpha = 0.4f),
+ .copy(alpha = SelectedContinerColorOpacity),
selectedContentColor: Color = MaterialTheme.colorScheme.onSecondaryContainer,
disabledContainerColor: Color = Color.Transparent,
disabledContentColor: Color = MaterialTheme.colorScheme.onSurface,
@@ -249,7 +260,7 @@
selectedBorder: Border = border,
disabledBorder: Border = border,
focusedSelectedBorder: Border = focusedBorder,
- focusedDisabledBorder: Border = DefaultBorder,
+ focusedDisabledBorder: Border = FocusedDisabledBorder,
pressedSelectedBorder: Border = border
) = ListItemBorder(
border = border,
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemStyles.kt b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemStyles.kt
index 03ae04a..abc3121 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/ListItemStyles.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/ListItemStyles.kt
@@ -17,25 +17,36 @@
package androidx.tv.material3
import androidx.annotation.FloatRange
-import androidx.compose.foundation.Indication
import androidx.compose.runtime.Immutable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
/**
- * Defines [Shape] for all TV [Indication] states of a ListItem.
+ * Represents the [Shape] of ListItem in different interaction states.
+ *
+ * @constructor create an instance with arbitrary shapes.
+ * See [ListItemDefaults.shape] for the default shapes used in a [ListItem].
+ *
+ * @param shape the shape used when the ListItem is enabled.
+ * @param focusedShape the shape used when the ListItem is enabled and focused.
+ * @param pressedShape the shape used when the ListItem is enabled and pressed.
+ * @param selectedShape the shape used when the ListItem is enabled and selected.
+ * @param disabledShape the shape used when the ListItem is not enabled.
+ * @param focusedSelectedShape the shape used when the ListItem is enabled, focused and selected.
+ * @param focusedDisabledShape the shape used when the ListItem is not enabled and focused.
+ * @param pressedSelectedShape the shape used when the ListItem is enabled, pressed and selected.
*/
@ExperimentalTvMaterial3Api
@Immutable
-class ListItemShape internal constructor(
- internal val shape: Shape,
- internal val focusedShape: Shape,
- internal val pressedShape: Shape,
- internal val selectedShape: Shape,
- internal val disabledShape: Shape,
- internal val focusedSelectedShape: Shape,
- internal val focusedDisabledShape: Shape,
- internal val pressedSelectedShape: Shape
+class ListItemShape constructor(
+ val shape: Shape,
+ val focusedShape: Shape,
+ val pressedShape: Shape,
+ val selectedShape: Shape,
+ val disabledShape: Shape,
+ val focusedSelectedShape: Shape,
+ val focusedDisabledShape: Shape,
+ val pressedSelectedShape: Shape
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -81,25 +92,48 @@
}
/**
- * Defines container & content color [Color] for all TV [Indication] states of a ListItem.
+ * Represents the container & content color [Color] of ListItem in different interaction states.
+ *
+ * @constructor create an instance with arbitrary colors.
+ * See [ListItemDefaults.colors] for the default colors used in a [ListItem].
+ *
+ * @param containerColor the container color used when the ListItem is enabled.
+ * @param contentColor the content color used when the ListItem is enabled.
+ * @param focusedContainerColor the container color used when the ListItem is enabled and focused.
+ * @param focusedContentColor the content color used when the ListItem is enabled and focused.
+ * @param pressedContainerColor the container color used when the ListItem is enabled and pressed.
+ * @param pressedContentColor the content color used when the ListItem is enabled and pressed.
+ * @param selectedContainerColor the container color used when the ListItem is enabled and
+ * selected.
+ * @param selectedContentColor the content color used when the ListItem is enabled and selected.
+ * @param disabledContainerColor the container color used when the ListItem is not enabled.
+ * @param disabledContentColor the content color used when the ListItem is not enabled.
+ * @param focusedSelectedContainerColor the container color used when the ListItem is enabled,
+ * focused and selected.
+ * @param focusedSelectedContentColor the content color used when the ListItem is enabled,
+ * focused and selected.
+ * @param pressedSelectedContainerColor the container color used when the ListItem is enabled,
+ * pressed and selected.
+ * @param pressedSelectedContentColor the content color used when the ListItem is enabled,
+ * pressed and selected.
*/
@ExperimentalTvMaterial3Api
@Immutable
-class ListItemColors internal constructor(
- internal val containerColor: Color,
- internal val contentColor: Color,
- internal val focusedContainerColor: Color,
- internal val focusedContentColor: Color,
- internal val pressedContainerColor: Color,
- internal val pressedContentColor: Color,
- internal val selectedContainerColor: Color,
- internal val selectedContentColor: Color,
- internal val disabledContainerColor: Color,
- internal val disabledContentColor: Color,
- internal val focusedSelectedContainerColor: Color,
- internal val focusedSelectedContentColor: Color,
- internal val pressedSelectedContainerColor: Color,
- internal val pressedSelectedContentColor: Color
+class ListItemColors constructor(
+ val containerColor: Color,
+ val contentColor: Color,
+ val focusedContainerColor: Color,
+ val focusedContentColor: Color,
+ val pressedContainerColor: Color,
+ val pressedContentColor: Color,
+ val selectedContainerColor: Color,
+ val selectedContentColor: Color,
+ val disabledContainerColor: Color,
+ val disabledContentColor: Color,
+ val focusedSelectedContainerColor: Color,
+ val focusedSelectedContentColor: Color,
+ val pressedSelectedContainerColor: Color,
+ val pressedSelectedContentColor: Color
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -162,20 +196,35 @@
}
/**
- * Defines the scale for all TV [Indication] states of a ListItem.
+ * Represents the scale [Float] of ListItem for different interaction states.
* Note: This scale must always be a non-negative float.
+ *
+ * @constructor create an instance with arbitrary scale factors.
+ * See [ListItemDefaults.scale] for the default scale factors used in a [ListItem].
+ *
+ * @param scale the scale used when the ListItem is enabled.
+ * @param focusedScale the scale used when the ListItem is enabled and focused.
+ * @param pressedScale the scale used when the ListItem is enabled and pressed.
+ * @param selectedScale the scale used when the ListItem is enabled and selected.
+ * @param disabledScale the scale used when the ListItem is not enabled.
+ * @param focusedSelectedScale the scale used when the ListItem is enabled, focused and
+ * selected.
+ * @param focusedDisabledScale the scale used when the ListItem is not enabled and
+ * focused.
+ * @param pressedSelectedScale the scale used when the ListItem is enabled, pressed and
+ * selected.
*/
@ExperimentalTvMaterial3Api
@Immutable
-class ListItemScale internal constructor(
- @FloatRange(from = 0.0) internal val scale: Float,
- @FloatRange(from = 0.0) internal val focusedScale: Float,
- @FloatRange(from = 0.0) internal val pressedScale: Float,
- @FloatRange(from = 0.0) internal val selectedScale: Float,
- @FloatRange(from = 0.0) internal val disabledScale: Float,
- @FloatRange(from = 0.0) internal val focusedSelectedScale: Float,
- @FloatRange(from = 0.0) internal val focusedDisabledScale: Float,
- @FloatRange(from = 0.0) internal val pressedSelectedScale: Float
+class ListItemScale constructor(
+ @FloatRange(from = 0.0) val scale: Float,
+ @FloatRange(from = 0.0) val focusedScale: Float,
+ @FloatRange(from = 0.0) val pressedScale: Float,
+ @FloatRange(from = 0.0) val selectedScale: Float,
+ @FloatRange(from = 0.0) val disabledScale: Float,
+ @FloatRange(from = 0.0) val focusedSelectedScale: Float,
+ @FloatRange(from = 0.0) val focusedDisabledScale: Float,
+ @FloatRange(from = 0.0) val pressedSelectedScale: Float
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -237,19 +286,33 @@
}
/**
- * Defines [Border] for all TV [Indication] states of a ListItem.
+ * Represents the [Border] of ListItem for different interaction states.
+ *
+ * @constructor create an instance with arbitrary borders.
+ * See [ListItemDefaults.border] for the default borders used in a [ListItem].
+ *
+ * @param border the [Border] used when the ListItem is enabled.
+ * @param focusedBorder the [Border] used when the ListItem is enabled and focused.
+ * @param pressedBorder the [Border] used when the ListItem is enabled and pressed.
+ * @param selectedBorder the [Border] used when the ListItem is enabled and selected.
+ * @param disabledBorder the [Border] used when the ListItem is not enabled.
+ * @param focusedSelectedBorder the [Border] used when the ListItem is enabled, focused and
+ * selected.
+ * @param focusedDisabledBorder the [Border] used when the ListItem is not enabled and focused.
+ * @param pressedSelectedBorder the [Border] used when the ListItem is enabled, pressed and
+ * selected.
*/
@ExperimentalTvMaterial3Api
@Immutable
-class ListItemBorder internal constructor(
- internal val border: Border,
- internal val focusedBorder: Border,
- internal val pressedBorder: Border,
- internal val selectedBorder: Border,
- internal val disabledBorder: Border,
- internal val focusedSelectedBorder: Border,
- internal val focusedDisabledBorder: Border,
- internal val pressedSelectedBorder: Border
+class ListItemBorder constructor(
+ val border: Border,
+ val focusedBorder: Border,
+ val pressedBorder: Border,
+ val selectedBorder: Border,
+ val disabledBorder: Border,
+ val focusedSelectedBorder: Border,
+ val focusedDisabledBorder: Border,
+ val pressedSelectedBorder: Border
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -295,17 +358,27 @@
}
/**
- * Defines [Glow] for all TV [Indication] states of a ListItem.
+ * Represents the [Glow] of ListItem for different interaction states.
+ *
+ * @constructor create an instance with arbitrary glows.
+ * See [ListItemDefaults.glow] for the default glows used in a [ListItem].
+ *
+ * @param glow the [Glow] used when the ListItem is enabled.
+ * @param focusedGlow the [Glow] used when the ListItem is enabled and focused.
+ * @param pressedGlow the [Glow] used when the ListItem is enabled and pressed.
+ * @param selectedGlow the [Glow] used when the ListItem is enabled and selected.
+ * @param focusedSelectedGlow the [Glow] used when the ListItem is enabled, focused and selected.
+ * @param pressedSelectedGlow the [Glow] used when the ListItem is enabled, pressed and selected.
*/
@ExperimentalTvMaterial3Api
@Immutable
-class ListItemGlow internal constructor(
- internal val glow: Glow,
- internal val focusedGlow: Glow,
- internal val pressedGlow: Glow,
- internal val selectedGlow: Glow,
- internal val focusedSelectedGlow: Glow,
- internal val pressedSelectedGlow: Glow
+class ListItemGlow constructor(
+ val glow: Glow,
+ val focusedGlow: Glow,
+ val pressedGlow: Glow,
+ val selectedGlow: Glow,
+ val focusedSelectedGlow: Glow,
+ val pressedSelectedGlow: Glow
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
diff --git a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
index ac34cff..a3f7e6d 100644
--- a/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
+++ b/tv/tv-material/src/main/java/androidx/tv/material3/NavigationDrawer.kt
@@ -40,7 +40,8 @@
import androidx.compose.ui.focus.FocusState
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
-import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
@@ -59,7 +60,8 @@
* layout grid.
*
* Example:
- * @sample androidx.tv.samples.SampleModalNavigationDrawer
+ * @sample androidx.tv.samples.SampleModalNavigationDrawerWithSolidScrim
+ * @sample androidx.tv.samples.SampleModalNavigationDrawerWithGradientScrim
*
* @param drawerContent Content that needs to be displayed on the drawer based on whether the drawer
* is [DrawerValue.Open] or [DrawerValue.Closed].
@@ -72,7 +74,7 @@
*
* @param modifier the [Modifier] to be applied to this drawer
* @param drawerState state of the drawer
- * @param scrimColor color of the scrim that obscures content when the drawer is open
+ * @param scrimBrush brush to paint the scrim that obscures content when the drawer is open
* @param content content of the rest of the UI
*/
@ExperimentalTvMaterial3Api
@@ -81,7 +83,7 @@
drawerContent: @Composable (DrawerValue) -> Unit,
modifier: Modifier = Modifier,
drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
- scrimColor: Color = LocalColorScheme.current.scrim.copy(alpha = 0.5f),
+ scrimBrush: Brush = SolidColor(LocalColorScheme.current.scrim.copy(alpha = 0.5f)),
content: @Composable () -> Unit
) {
val localDensity = LocalDensity.current
@@ -113,14 +115,14 @@
content = drawerContent
)
+ if (drawerState.currentValue == DrawerValue.Open) {
+ // Scrim
+ Canvas(Modifier.fillMaxSize()) {
+ drawRect(scrimBrush)
+ }
+ }
Box(Modifier.padding(start = closedDrawerWidth.value ?: ClosedDrawerWidth.dp)) {
content()
- if (drawerState.currentValue == DrawerValue.Open) {
- // Scrim
- Canvas(Modifier.fillMaxSize()) {
- drawRect(scrimColor)
- }
- }
}
}
}
diff --git a/tvprovider/tvprovider/api/api_lint.ignore b/tvprovider/tvprovider/api/api_lint.ignore
index 60a676a..16230a6 100644
--- a/tvprovider/tvprovider/api/api_lint.ignore
+++ b/tvprovider/tvprovider/api/api_lint.ignore
@@ -81,13 +81,9 @@
Public class androidx.tvprovider.media.tv.WatchNextProgram stripped of unavailable superclass androidx.tvprovider.media.tv.BasePreviewProgram
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_COUNT:
+IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns#COLUMN_INTERACTION_COUNT:
Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_COUNT
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_TYPE:
- Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_TYPE
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms#COLUMN_INTERACTION_COUNT:
- Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_COUNT
-IntentName: androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms#COLUMN_INTERACTION_TYPE:
+IntentName: androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns#COLUMN_INTERACTION_TYPE:
Intent action constant name must be ACTION_FOO: COLUMN_INTERACTION_TYPE
diff --git a/tvprovider/tvprovider/api/current.txt b/tvprovider/tvprovider/api/current.txt
index c82fb20..1ca7bb2 100644
--- a/tvprovider/tvprovider/api/current.txt
+++ b/tvprovider/tvprovider/api/current.txt
@@ -195,6 +195,7 @@
method public boolean isSearchable();
method public boolean isTransient();
method public android.content.ContentValues! toContentValues();
+ field public static final String![] PROJECTION;
}
public static final class PreviewProgram.Builder {
@@ -458,7 +459,7 @@
field public static final String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContractCompat.PreviewPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns {
+ public static interface TvContractCompat.PreviewProgramColumns {
field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
@@ -472,62 +473,33 @@
field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
- field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final String COLUMN_AUTHOR = "author";
field public static final String COLUMN_AVAILABILITY = "availability";
field public static final String COLUMN_BROWSABLE = "browsable";
- field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final String COLUMN_CHANNEL_ID = "channel_id";
field public static final String COLUMN_CONTENT_ID = "content_id";
- field public static final String COLUMN_CONTENT_RATING = "content_rating";
field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
- field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
- field public static final String COLUMN_EPISODE_TITLE = "episode_title";
field public static final String COLUMN_GENRE = "genre";
field public static final String COLUMN_INTENT_URI = "intent_uri";
field public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
field public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
- field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
- field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
- field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
- field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
field public static final String COLUMN_ITEM_COUNT = "item_count";
field public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
field public static final String COLUMN_LIVE = "live";
field public static final String COLUMN_LOGO_CONTENT_DESCRIPTION = "logo_content_description";
field public static final String COLUMN_LOGO_URI = "logo_uri";
- field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
field public static final String COLUMN_OFFER_PRICE = "offer_price";
field public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
field public static final String COLUMN_PREVIEW_AUDIO_URI = "preview_audio_uri";
field public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
field public static final String COLUMN_RELEASE_DATE = "release_date";
- field public static final String COLUMN_REVIEW_RATING = "review_rating";
- field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final String COLUMN_SEARCHABLE = "searchable";
- field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
- field public static final String COLUMN_SEASON_TITLE = "season_title";
- field public static final String COLUMN_SERIES_ID = "series_id";
- field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
field public static final String COLUMN_STARTING_PRICE = "starting_price";
field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
- field public static final String COLUMN_TITLE = "title";
field public static final String COLUMN_TRANSIENT = "transient";
field public static final String COLUMN_TV_SERIES_ITEM_TYPE = "tv_series_item_type";
field public static final String COLUMN_TYPE = "type";
- field public static final String COLUMN_VERSION_NUMBER = "version_number";
- field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
- field public static final String COLUMN_VIDEO_WIDTH = "video_width";
- field public static final String COLUMN_WEIGHT = "weight";
- field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
- field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
- field public static final android.net.Uri! CONTENT_URI;
field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4
@@ -535,9 +507,6 @@
field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5
field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6
field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0
- field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
- field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
- field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
field public static final int TV_SERIES_ITEM_TYPE_CHAPTER = 1; // 0x1
field public static final int TV_SERIES_ITEM_TYPE_EPISODE = 0; // 0x0
field public static final int TYPE_ALBUM = 8; // 0x8
@@ -555,6 +524,41 @@
field public static final int TYPE_TV_SERIES = 1; // 0x1
}
+ public static final class TvContractCompat.PreviewPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns {
+ field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+ field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+ field public static final String COLUMN_CHANNEL_ID = "channel_id";
+ field public static final String COLUMN_CONTENT_RATING = "content_rating";
+ field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
+ field public static final String COLUMN_EPISODE_TITLE = "episode_title";
+ field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
+ field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
+ field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
+ field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
+ field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
+ field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+ field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
+ field public static final String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final String COLUMN_SEARCHABLE = "searchable";
+ field public static final String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
+ field public static final String COLUMN_SEASON_TITLE = "season_title";
+ field public static final String COLUMN_SERIES_ID = "series_id";
+ field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+ field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
+ field public static final String COLUMN_TITLE = "title";
+ field public static final String COLUMN_VERSION_NUMBER = "version_number";
+ field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
+ field public static final String COLUMN_VIDEO_WIDTH = "video_width";
+ field public static final String COLUMN_WEIGHT = "weight";
+ field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
+ field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
+ field public static final android.net.Uri! CONTENT_URI;
+ field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
+ field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
+ field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
+ }
+
public static final class TvContractCompat.Programs implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns {
field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
@@ -662,54 +666,20 @@
field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
}
- public static final class TvContractCompat.WatchNextPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns {
- field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
- field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
- field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
- field public static final int ASPECT_RATIO_3_2 = 1; // 0x1
- field public static final int ASPECT_RATIO_3_4 = 6; // 0x6
- field public static final int ASPECT_RATIO_4_3 = 2; // 0x2
- field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
- field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
- field public static final int AVAILABILITY_FREE = 4; // 0x4
- field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
- field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
- field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
- field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
+ public static final class TvContractCompat.WatchNextPrograms implements androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns {
field public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
- field public static final String COLUMN_AUTHOR = "author";
- field public static final String COLUMN_AVAILABILITY = "availability";
- field public static final String COLUMN_BROWSABLE = "browsable";
field public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final String COLUMN_CONTENT_ID = "content_id";
field public static final String COLUMN_CONTENT_RATING = "content_rating";
- field public static final String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final String COLUMN_EPISODE_TITLE = "episode_title";
- field public static final String COLUMN_GENRE = "genre";
- field public static final String COLUMN_INTENT_URI = "intent_uri";
- field public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
field public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
field public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
field public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
field public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
field public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
- field public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final String COLUMN_ITEM_COUNT = "item_count";
field public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
- field public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final String COLUMN_LIVE = "live";
- field public static final String COLUMN_LOGO_CONTENT_DESCRIPTION = "logo_content_description";
- field public static final String COLUMN_LOGO_URI = "logo_uri";
field public static final String COLUMN_LONG_DESCRIPTION = "long_description";
- field public static final String COLUMN_OFFER_PRICE = "offer_price";
- field public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
field public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
- field public static final String COLUMN_PREVIEW_AUDIO_URI = "preview_audio_uri";
- field public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final String COLUMN_RELEASE_DATE = "release_date";
field public static final String COLUMN_REVIEW_RATING = "review_rating";
field public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
field public static final String COLUMN_SEARCHABLE = "searchable";
@@ -717,14 +687,8 @@
field public static final String COLUMN_SEASON_TITLE = "season_title";
field public static final String COLUMN_SERIES_ID = "series_id";
field public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
- field public static final String COLUMN_STARTING_PRICE = "starting_price";
- field public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
- field public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
field public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
field public static final String COLUMN_TITLE = "title";
- field public static final String COLUMN_TRANSIENT = "transient";
- field public static final String COLUMN_TV_SERIES_ITEM_TYPE = "tv_series_item_type";
- field public static final String COLUMN_TYPE = "type";
field public static final String COLUMN_VERSION_NUMBER = "version_number";
field public static final String COLUMN_VIDEO_HEIGHT = "video_height";
field public static final String COLUMN_VIDEO_WIDTH = "video_width";
@@ -732,31 +696,9 @@
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
field public static final android.net.Uri! CONTENT_URI;
- field public static final int INTERACTION_TYPE_FANS = 3; // 0x3
- field public static final int INTERACTION_TYPE_FOLLOWERS = 2; // 0x2
- field public static final int INTERACTION_TYPE_LIKES = 4; // 0x4
- field public static final int INTERACTION_TYPE_LISTENS = 1; // 0x1
- field public static final int INTERACTION_TYPE_THUMBS = 5; // 0x5
- field public static final int INTERACTION_TYPE_VIEWERS = 6; // 0x6
- field public static final int INTERACTION_TYPE_VIEWS = 0; // 0x0
field public static final int REVIEW_RATING_STYLE_PERCENTAGE = 2; // 0x2
field public static final int REVIEW_RATING_STYLE_STARS = 0; // 0x0
field public static final int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1; // 0x1
- field public static final int TV_SERIES_ITEM_TYPE_CHAPTER = 1; // 0x1
- field public static final int TV_SERIES_ITEM_TYPE_EPISODE = 0; // 0x0
- field public static final int TYPE_ALBUM = 8; // 0x8
- field public static final int TYPE_ARTIST = 9; // 0x9
- field public static final int TYPE_CHANNEL = 6; // 0x6
- field public static final int TYPE_CLIP = 4; // 0x4
- field public static final int TYPE_EVENT = 5; // 0x5
- field public static final int TYPE_GAME = 12; // 0xc
- field public static final int TYPE_MOVIE = 0; // 0x0
- field public static final int TYPE_PLAYLIST = 10; // 0xa
- field public static final int TYPE_STATION = 11; // 0xb
- field public static final int TYPE_TRACK = 7; // 0x7
- field public static final int TYPE_TV_EPISODE = 3; // 0x3
- field public static final int TYPE_TV_SEASON = 2; // 0x2
- field public static final int TYPE_TV_SERIES = 1; // 0x1
field public static final int WATCH_NEXT_TYPE_CONTINUE = 0; // 0x0
field public static final int WATCH_NEXT_TYPE_NEW = 2; // 0x2
field public static final int WATCH_NEXT_TYPE_NEXT = 1; // 0x1
@@ -821,6 +763,7 @@
method public boolean isSearchable();
method public boolean isTransient();
method public android.content.ContentValues! toContentValues();
+ field public static final String![] PROJECTION;
field public static final int WATCH_NEXT_TYPE_UNKNOWN = -1; // 0xffffffff
}
diff --git a/tvprovider/tvprovider/api/restricted_current.txt b/tvprovider/tvprovider/api/restricted_current.txt
index aa21de7..217e357 100644
--- a/tvprovider/tvprovider/api/restricted_current.txt
+++ b/tvprovider/tvprovider/api/restricted_current.txt
@@ -224,7 +224,7 @@
method public boolean isTransient();
method public android.content.ContentValues! toContentValues();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.ContentValues! toContentValues(boolean);
- field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String![]! PROJECTION;
+ field public static final String![] PROJECTION;
}
public static final class PreviewProgram.Builder {
@@ -517,7 +517,7 @@
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @StringDef({androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_SD, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_ED, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_HD, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_FHD, androidx.tvprovider.media.tv.TvContractCompat.Channels.VIDEO_RESOLUTION_UHD}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface TvContractCompat.Channels.VideoResolution {
}
- @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface TvContractCompat.PreviewProgramColumns {
+ public static interface TvContractCompat.PreviewProgramColumns {
field public static final int ASPECT_RATIO_16_9 = 0; // 0x0
field public static final int ASPECT_RATIO_1_1 = 3; // 0x3
field public static final int ASPECT_RATIO_2_3 = 4; // 0x4
@@ -829,7 +829,7 @@
method public boolean isTransient();
method public android.content.ContentValues! toContentValues();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.ContentValues! toContentValues(boolean);
- field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String![]! PROJECTION;
+ field public static final String![] PROJECTION;
field public static final int WATCH_NEXT_TYPE_UNKNOWN = -1; // 0xffffffff
}
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
index afe4160..9a6037a 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/PreviewProgram.java
@@ -21,6 +21,7 @@
import android.database.Cursor;
import android.os.Build;
+import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms;
@@ -76,8 +77,12 @@
*/
public final class PreviewProgram extends BasePreviewProgram {
/**
+ * The projection for a {@link PreviewProgram} query.
+ * <p> This provides a array of strings containing the columns to be used in the
+ * query and in creating a Cursor object, which is used to iterate through the rows in the
+ * table.
*/
- @RestrictTo(LIBRARY_GROUP_PREFIX)
+ @NonNull
public static final String[] PROJECTION = getProjection();
private static final long INVALID_LONG_VALUE = -1;
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
index 7d72b57..2725306 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
@@ -914,7 +914,6 @@
/**
* Common columns for the tables of preview programs.
*/
- @RestrictTo(LIBRARY_GROUP_PREFIX)
public interface PreviewProgramColumns {
/**
* The program type for movie.
diff --git a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
index edcb4d1..475aa87 100644
--- a/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
+++ b/tvprovider/tvprovider/src/main/java/androidx/tvprovider/media/tv/WatchNextProgram.java
@@ -22,6 +22,7 @@
import android.os.Build;
import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms;
@@ -79,8 +80,12 @@
*/
public final class WatchNextProgram extends BasePreviewProgram {
/**
+ * The projection for a {@link WatchNextProgram} query.
+ * <p> This provides a array of strings containing the columns to be used in the
+ * query and in creating a Cursor object, which is used to iterate through the rows in the
+ * table.
*/
- @RestrictTo(LIBRARY_GROUP_PREFIX)
+ @NonNull
public static final String[] PROJECTION = getProjection();
private static final long INVALID_LONG_VALUE = -1;
diff --git a/wear/compose/compose-foundation/api/current.txt b/wear/compose/compose-foundation/api/current.txt
index 2730513d..d723269 100644
--- a/wear/compose/compose-foundation/api/current.txt
+++ b/wear/compose/compose-foundation/api/current.txt
@@ -139,7 +139,7 @@
public final class CurvedParentDataKt {
method public static androidx.wear.compose.foundation.CurvedModifier parentDataModifier(androidx.wear.compose.foundation.CurvedModifier, kotlin.jvm.functions.Function1<java.lang.Object,?> modifyParentData);
- method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, float weight);
+ method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, fromInclusive=false) float weight);
}
public final class CurvedRowKt {
@@ -153,8 +153,8 @@
method public static androidx.wear.compose.foundation.CurvedModifier angularSize(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees);
method public static androidx.wear.compose.foundation.CurvedModifier angularSizeDp(androidx.wear.compose.foundation.CurvedModifier, float angularWidth);
method public static androidx.wear.compose.foundation.CurvedModifier radialSize(androidx.wear.compose.foundation.CurvedModifier, float thickness);
- method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees, float thickness);
- method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional float minSweepDegrees, optional float maxSweepDegrees, optional float minThickness, optional float maxThickness);
+ method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, to=360.0) float sweepDegrees, float thickness);
+ method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional @FloatRange(from=0.0, to=360.0) float minSweepDegrees, optional @FloatRange(from=0.0, to=360.0) float maxSweepDegrees, optional float minThickness, optional float maxThickness);
}
public final class CurvedTextStyle {
@@ -357,9 +357,9 @@
}
@androidx.compose.runtime.Stable @androidx.wear.compose.foundation.lazy.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
- method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
- method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
- method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+ method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
}
public sealed interface ScalingLazyListLayoutInfo {
@@ -426,20 +426,20 @@
}
@androidx.compose.runtime.Stable public interface ScalingParams {
- method public float getEdgeAlpha();
- method public float getEdgeScale();
- method public float getMaxElementHeight();
- method public float getMaxTransitionArea();
- method public float getMinElementHeight();
- method public float getMinTransitionArea();
+ method @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+ method @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+ method @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+ method @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+ method @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+ method @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
method public androidx.compose.animation.core.Easing getScaleInterpolator();
method public int resolveViewportVerticalOffset(long viewportConstraints);
- property public abstract float edgeAlpha;
- property public abstract float edgeScale;
- property public abstract float maxElementHeight;
- property public abstract float maxTransitionArea;
- property public abstract float minElementHeight;
- property public abstract float minTransitionArea;
+ property @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+ property @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+ property @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+ property @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+ property @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+ property @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
property public abstract androidx.compose.animation.core.Easing scaleInterpolator;
}
diff --git a/wear/compose/compose-foundation/api/restricted_current.txt b/wear/compose/compose-foundation/api/restricted_current.txt
index 2730513d..d723269 100644
--- a/wear/compose/compose-foundation/api/restricted_current.txt
+++ b/wear/compose/compose-foundation/api/restricted_current.txt
@@ -139,7 +139,7 @@
public final class CurvedParentDataKt {
method public static androidx.wear.compose.foundation.CurvedModifier parentDataModifier(androidx.wear.compose.foundation.CurvedModifier, kotlin.jvm.functions.Function1<java.lang.Object,?> modifyParentData);
- method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, float weight);
+ method public static androidx.wear.compose.foundation.CurvedModifier weight(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, fromInclusive=false) float weight);
}
public final class CurvedRowKt {
@@ -153,8 +153,8 @@
method public static androidx.wear.compose.foundation.CurvedModifier angularSize(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees);
method public static androidx.wear.compose.foundation.CurvedModifier angularSizeDp(androidx.wear.compose.foundation.CurvedModifier, float angularWidth);
method public static androidx.wear.compose.foundation.CurvedModifier radialSize(androidx.wear.compose.foundation.CurvedModifier, float thickness);
- method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, float sweepDegrees, float thickness);
- method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional float minSweepDegrees, optional float maxSweepDegrees, optional float minThickness, optional float maxThickness);
+ method public static androidx.wear.compose.foundation.CurvedModifier size(androidx.wear.compose.foundation.CurvedModifier, @FloatRange(from=0.0, to=360.0) float sweepDegrees, float thickness);
+ method public static androidx.wear.compose.foundation.CurvedModifier sizeIn(androidx.wear.compose.foundation.CurvedModifier, optional @FloatRange(from=0.0, to=360.0) float minSweepDegrees, optional @FloatRange(from=0.0, to=360.0) float maxSweepDegrees, optional float minThickness, optional float maxThickness);
}
public final class CurvedTextStyle {
@@ -357,9 +357,9 @@
}
@androidx.compose.runtime.Stable @androidx.wear.compose.foundation.lazy.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
- method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
- method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
- method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+ method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
}
public sealed interface ScalingLazyListLayoutInfo {
@@ -426,20 +426,20 @@
}
@androidx.compose.runtime.Stable public interface ScalingParams {
- method public float getEdgeAlpha();
- method public float getEdgeScale();
- method public float getMaxElementHeight();
- method public float getMaxTransitionArea();
- method public float getMinElementHeight();
- method public float getMinTransitionArea();
+ method @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+ method @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+ method @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+ method @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+ method @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+ method @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
method public androidx.compose.animation.core.Easing getScaleInterpolator();
method public int resolveViewportVerticalOffset(long viewportConstraints);
- property public abstract float edgeAlpha;
- property public abstract float edgeScale;
- property public abstract float maxElementHeight;
- property public abstract float maxTransitionArea;
- property public abstract float minElementHeight;
- property public abstract float minTransitionArea;
+ property @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+ property @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+ property @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+ property @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+ property @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+ property @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
property public abstract androidx.compose.animation.core.Easing scaleInterpolator;
}
diff --git a/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListLayoutInfoTest.kt b/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListLayoutInfoTest.kt
index a04f924..cf0399d 100644
--- a/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListLayoutInfoTest.kt
+++ b/wear/compose/compose-foundation/src/androidTest/kotlin/androidx/wear/compose/foundation/lazy/ScalingLazyListLayoutInfoTest.kt
@@ -133,6 +133,7 @@
scope!!.launch {
state.animateScrollBy(scrollDistance.toFloat())
}
+
rule.runOnIdle {
assertThat(state.centerItemIndex).isEqualTo(1)
assertThat(state.centerItemScrollOffset).isEqualTo(scrollDistance)
@@ -419,6 +420,7 @@
}
}
}
+ rule.mainClock.autoAdvance = false
// TODO(b/210654937): Remove the waitUntil once we no longer need 2 stage initialization
rule.waitUntil { state.initialized.value }
@@ -426,7 +428,8 @@
state.animateScrollBy(localItemSizePx.toFloat() * 10)
}
- rule.waitUntil { !state.isScrollInProgress }
+ rule.mainClock.advanceTimeBy(milliseconds = 1000)
+ assert(!state.isScrollInProgress)
assertThat(state.centerItemIndex).isEqualTo(4)
assertThat(state.centerItemScrollOffset).isEqualTo(0)
@@ -434,7 +437,8 @@
state.animateScrollBy(- localItemSizePx.toFloat() * 10)
}
- rule.waitUntil { !state.isScrollInProgress }
+ rule.mainClock.advanceTimeBy(milliseconds = 1000)
+ assert(!state.isScrollInProgress)
assertThat(state.centerItemIndex).isEqualTo(autoCenterItem)
assertThat(state.centerItemScrollOffset).isEqualTo(0)
}
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt
index aedafea..14d4b39 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedParentData.kt
@@ -16,6 +16,8 @@
package androidx.wear.compose.foundation
+import androidx.annotation.FloatRange
+
/**
* A [CurvedModifier] that provides data to the parent layout.
* The parent data is commonly used to inform the parent how the child Layout should be measured
@@ -41,7 +43,7 @@
* all weighted siblings. Must be positive.
*/
public fun CurvedModifier.weight(
- /* @FloatRange(from = 0f, fromInclusive = false) */
+ @FloatRange(from = 0.0, fromInclusive = false)
weight: Float
) = parentDataModifier { parentData ->
require(weight > 0f) { "Weights must be positive." }
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt
index 8e0408c..6c90d7a 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/CurvedSize.kt
@@ -16,6 +16,7 @@
package androidx.wear.compose.foundation
+import androidx.annotation.FloatRange
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.unit.Dp
@@ -30,9 +31,9 @@
* @param maxThickness the maximum thickness (radial size) for the content.
*/
public fun CurvedModifier.sizeIn(
- /* @FloatRange(from = 0f, to = 360f) */
+ @FloatRange(from = 0.0, to = 360.0)
minSweepDegrees: Float = 0f,
- /* @FloatRange(from = 0f, to = 360f) */
+ @FloatRange(from = 0.0, to = 360.0)
maxSweepDegrees: Float = 360f,
minThickness: Dp = 0.dp,
maxThickness: Dp = Dp.Infinity,
@@ -54,10 +55,12 @@
* @param sweepDegrees Indicates the sweep (angular size) of the content.
* @param thickness Indicates the thickness (radial size) of the content.
*/
-public fun CurvedModifier.size(sweepDegrees: Float, thickness: Dp) = sizeIn(
- /* @FloatRange(from = 0f, to = 360f) */
+public fun CurvedModifier.size(
+ @FloatRange(from = 0.0, to = 360.0)
+ sweepDegrees: Float,
+ thickness: Dp
+) = sizeIn(
minSweepDegrees = sweepDegrees,
- /* @FloatRange(from = 0f, to = 360f) */
maxSweepDegrees = sweepDegrees,
minThickness = thickness,
maxThickness = thickness
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt
index 2f4d683..7662003 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeToReveal.kt
@@ -260,10 +260,10 @@
*
* @param action The mandatory action that needs to be added to the component.
* @param modifier Optional [Modifier] for this component.
- * @param state The [RevealState] of this component. It can be used to customise the anchors
- * and threshold config of the swipeable modifier which is applied.
* @param onFullSwipe An optional lambda which will be triggered when a full swipe from either of
* the anchors is performed.
+ * @param state The [RevealState] of this component. It can be used to customise the anchors
+ * and threshold config of the swipeable modifier which is applied.
* @param additionalAction The optional action that can be added to the component.
* @param undoAction The optional undo action that will be applied to the component once the
* mandatory action has been performed.
@@ -388,12 +388,13 @@
* anchor for [RevealValue.Revealing].
* If there is no such anchor defined for [RevealValue.Revealing], it returns 0.0f.
*/
+ /* @FloatRange(from = 0.0) */
public val revealOffset: Float
}
@OptIn(ExperimentalWearFoundationApi::class)
private class RevealScopeImpl constructor(
- private val revealState: RevealState
+ val revealState: RevealState,
) : RevealScope {
/**
@@ -430,7 +431,9 @@
content: @Composable RevealScope.() -> Unit
) {
Box(
- modifier = modifier.fillMaxHeight().weight(weight),
+ modifier = modifier
+ .fillMaxHeight()
+ .weight(weight),
contentAlignment = Alignment.Center
) {
with(revealScope) {
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
index 15a2dde..ff97315 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/SwipeableV2.kt
@@ -16,6 +16,7 @@
package androidx.wear.compose.foundation
+import androidx.annotation.FloatRange
import androidx.annotation.RestrictTo
import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
import androidx.compose.animation.core.AnimationSpec
@@ -296,7 +297,7 @@
* The fraction of the progress going from [currentValue] to [targetValue], within [0f..1f]
* bounds.
*/
- /*@FloatRange(from = 0f, to = 1f)*/
+ @get:FloatRange(from = 0.0, to = 1.0)
val progress: Float by derivedStateOf {
val a = anchors[currentValue] ?: 0f
val b = anchors[targetValue] ?: 0f
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt
index 7a6eba0..677dca7 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumn.kt
@@ -34,11 +34,11 @@
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -58,6 +58,7 @@
import androidx.compose.ui.unit.offset
import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
import androidx.wear.compose.foundation.LocalReduceMotion
+import kotlinx.coroutines.launch
/**
* Receiver scope which is used by [ScalingLazyColumn].
@@ -395,6 +396,7 @@
state.reverseLayout.value = reverseLayout
state.localInspectionMode.value = LocalInspectionMode.current
+ val coroutineScope = rememberCoroutineScope()
LazyColumn(
modifier = Modifier
.clipToBounds()
@@ -406,6 +408,9 @@
layoutInfo.readyForInitialScroll
) {
initialized = true
+ coroutineScope.launch {
+ state.scrollToInitialItem()
+ }
}
},
horizontalAlignment = horizontalAlignment,
@@ -443,11 +448,6 @@
}
}
}
- if (initialized) {
- LaunchedEffect(state) {
- state.scrollToInitialItem()
- }
- }
}
}
}
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
index 9f65cce..7584d68 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyColumnMeasure.kt
@@ -16,6 +16,7 @@
package androidx.wear.compose.foundation.lazy
+import androidx.annotation.FloatRange
import androidx.annotation.RestrictTo
import androidx.compose.animation.core.Easing
import androidx.compose.foundation.gestures.Orientation
@@ -100,9 +101,7 @@
* scaled, e.g. at the edge of the viewport. A value between [0f,1f], so a value of 0.2f
* means to scale an item to 20% of its normal size.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val edgeScale: Float
/**
@@ -110,9 +109,7 @@
* when closest to the edge of the screen. A value between [0f,1f], so a value of
* 0.2f means to set the alpha of an item to 20% of its normal value.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val edgeAlpha: Float
/**
@@ -122,9 +119,7 @@
* will be treated as if [maxElementHeight]. Must be greater than or equal to
* [minElementHeight].
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val minElementHeight: Float
/**
@@ -134,9 +129,7 @@
* will be treated as if [maxElementHeight]. Must be greater than or equal to
* [minElementHeight].
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val maxElementHeight: Float
/**
@@ -153,9 +146,7 @@
* list items exist. Depending on the size of the list item the specific point in the area is
* calculated.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val minTransitionArea: Float
/**
@@ -172,9 +163,7 @@
* list items exist. Depending on the size of the list item the specific point in the area is
* calculated.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val maxTransitionArea: Float
/**
diff --git a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt
index 042e928..aac594e 100644
--- a/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt
+++ b/wear/compose/compose-foundation/src/main/java/androidx/wear/compose/foundation/lazy/ScalingLazyListItemScope.kt
@@ -15,6 +15,7 @@
*/
package androidx.wear.compose.foundation.lazy
+import androidx.annotation.FloatRange
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
@@ -42,7 +43,7 @@
* measured with [Constraints.Infinity] as the constraints for the main axis.
*/
fun Modifier.fillParentMaxSize(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
fraction: Float = 1f
): Modifier
@@ -57,7 +58,7 @@
* items are measured with [Constraints.Infinity] as the constraints for the main axis.
*/
fun Modifier.fillParentMaxWidth(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
fraction: Float = 1f
): Modifier
@@ -72,7 +73,7 @@
* items are measured with [Constraints.Infinity] as the constraints for the main axis.
*/
fun Modifier.fillParentMaxHeight(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
fraction: Float = 1f
): Modifier
}
diff --git a/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/SelectionControlsTest.kt b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/SelectionControlsTest.kt
index ef4b18f..8cb1df6 100644
--- a/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/SelectionControlsTest.kt
+++ b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/SelectionControlsTest.kt
@@ -242,7 +242,7 @@
}
@Test
- fun checkbox_is_off_when_checked() {
+ fun checkbox_is_off_when_unchecked() {
// This test only applies when onCheckedChange is defined.
rule.setContent {
CheckboxWithDefaults(
@@ -467,7 +467,7 @@
}
@Test
- fun switch_is_off_when_checked() {
+ fun switch_is_off_when_unchecked() {
// This test only applies when onCheckedChange is defined.
rule.setContent {
SwitchWithDefaults(
@@ -852,7 +852,7 @@
enabled: Boolean = true,
onCheckedChange: ((Boolean) -> Unit)? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
- drawBox: FunctionDrawBox = FunctionDrawBox { _, _, _ -> },
+ drawBox: FunctionDrawBox = FunctionDrawBox { _, _, _, _ -> },
width: Dp = 24.dp,
height: Dp = 24.dp
) = Checkbox(
@@ -1003,7 +1003,7 @@
disabledUncheckedColor = checkmarkColorDisabledUnchecked
)
},
- drawBox = { drawScope, color, _ ->
+ drawBox = { drawScope, color, _, _ ->
drawScope.drawRoundRect(color)
})
}
diff --git a/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/ToggleButtonTest.kt b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/ToggleButtonTest.kt
new file mode 100644
index 0000000..6bd0e3c
--- /dev/null
+++ b/wear/compose/compose-material-core/src/androidTest/kotlin/androidx/wear/compose/materialcore/ToggleButtonTest.kt
@@ -0,0 +1,1154 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.materialcore
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.background
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.foundation.shape.CutCornerShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.State
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.compositeOver
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertHeightIsEqualTo
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.assertTouchHeightIsEqualTo
+import androidx.compose.ui.test.assertTouchWidthIsEqualTo
+import androidx.compose.ui.test.assertWidthIsEqualTo
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.isToggleable
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChildAt
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+class ToggleButtonTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ /* Round Toggle buttons */
+ @Test
+ fun round_toggle_button_supports_testTag() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun round_toggle_button_is_toggleable() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNode(isToggleable()).assertExists()
+ }
+
+ @Test
+ fun round_toggle_button_has_click_action_when_enabled() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+ }
+
+ @Test
+ fun round_toggle_button_has_click_action_when_disabled() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+ }
+
+ @Test
+ fun round_toggle_button_is_correctly_enabled() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+ }
+
+ @Test
+ fun round_toggle_button_is_correctly_disabled() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsNotEnabled()
+ }
+
+ @Test
+ fun round_toggle_button_is_on_when_checked() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = true,
+ checked = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsOn()
+ }
+
+ @Test
+ fun round_toggle_button_is_off_when_unchecked() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = true,
+ checked = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsOff()
+ }
+
+ @Test
+ fun round_toggle_button_toggles_when_enabled() {
+ var clicked = false
+
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ enabled = true,
+ onCheckedChange = { clicked = true },
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performClick()
+
+ rule.runOnIdle {
+ Assert.assertEquals(true, clicked)
+ }
+ }
+
+ @Test
+ fun round_toggle_button_responds_to_toggle_on() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ RoundToggleButtonWithDefaults(
+ content = { TestImage() },
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOff()
+ .performClick()
+ .assertIsOn()
+ }
+
+ @Test
+ fun round_toggle_button_responds_to_toggle_off() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(true) }
+ RoundToggleButtonWithDefaults(
+ content = { TestImage() },
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOn()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun round_toggle_button_does_not_respond_to_click_when_disabled() {
+ var clicked = false
+
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ onCheckedChange = { clicked = true },
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).performClick()
+
+ rule.runOnIdle {
+ Assert.assertEquals(false, clicked)
+ }
+ }
+
+ @Test
+ fun round_toggle_button_has_role_checkbox() {
+ rule.setContent {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Checkbox
+ )
+ )
+ }
+
+ @Test
+ fun round_toggle_button_supports_circle_shape_under_ltr() =
+ rule.isShape(CircleShape, LayoutDirection.Ltr) {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ ) { }
+ }
+
+ @Test
+ fun round_toggle_button_supports_circle_shape_under_rtl() =
+ rule.isShape(CircleShape, LayoutDirection.Rtl) {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG),
+ ) { }
+ }
+
+ @Test
+ fun extra_small_round_toggle_button_meets_accessibility_tapSize() {
+ verifyTapSize(48.dp) {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier
+ .testTag(TEST_TAG)
+ .size(32.dp)
+ )
+ }
+ }
+
+ @Test
+ fun extra_small_round_toggle_button_has_correct_visible_size() {
+ verifyVisibleSize(32.dp) {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier
+ .testTag(TEST_TAG)
+ .requiredSize(32.dp)
+ )
+ }
+ }
+
+ @Test
+ fun default_round_toggle_button_has_correct_tapSize() {
+ // Tap size for Button should be 52.dp.
+ verifyTapSize(52.dp) {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier
+ .testTag(TEST_TAG)
+ .size(52.dp)
+ )
+ }
+ }
+
+ @Test
+ fun default_round_toggle_button_has_correct_visible_size() {
+ // Tap size for Button should be 52.dp.
+ verifyVisibleSize(52.dp) {
+ RoundToggleButtonWithDefaults(
+ modifier = Modifier
+ .testTag(TEST_TAG)
+ .size(52.dp)
+ )
+ }
+ }
+
+ @Test
+ fun round_toggle_button_allows_custom_shape_override() {
+ val shape = CutCornerShape(4.dp)
+
+ rule.isShape(shape, LayoutDirection.Ltr) {
+ RoundToggleButtonWithDefaults(
+ shape = shape,
+ modifier = Modifier.testTag(TEST_TAG)
+ ) { }
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun round_toggle_button_gives_correct_colors_when_enabled() =
+ verifyToggleButtonColors(
+ enabled = true,
+ checked = false,
+ { enabled, _ -> remember { mutableStateOf(if (enabled) Color.Green else Color.Red) } },
+ { enabled, _ ->
+ remember { mutableStateOf(if (enabled) Color.Blue else Color.Yellow) }
+ },
+ Color.Green,
+ Color.Blue
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun round_toggle_button_gives_correct_colors_when_disabled() =
+ verifyToggleButtonColors(
+ enabled = false,
+ checked = false,
+ { enabled, _ -> remember { mutableStateOf(if (enabled) Color.Green else Color.Red) } },
+ { enabled, _ ->
+ remember { mutableStateOf(if (enabled) Color.Blue else Color.Yellow) }
+ },
+ Color.Red,
+ Color.Yellow,
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun round_toggle_button_gives_correct_colors_when_checked() =
+ verifyToggleButtonColors(
+ enabled = true,
+ checked = true,
+ { _, checked -> remember { mutableStateOf(if (checked) Color.Green else Color.Red) } },
+ { _, checked ->
+ remember { mutableStateOf(if (checked) Color.Blue else Color.Yellow) }
+ },
+ Color.Green,
+ Color.Blue,
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun round_toggle_button_gives_correct_colors_when_unchecked() =
+ verifyToggleButtonColors(
+ enabled = true,
+ checked = false,
+ { _, checked -> remember { mutableStateOf(if (checked) Color.Green else Color.Red) } },
+ { _, checked ->
+ remember { mutableStateOf(if (checked) Color.Blue else Color.Yellow) }
+ },
+ Color.Red,
+ Color.Yellow,
+ )
+
+ @Test
+ fun round_toggle_button_obeys_content_provider_values() {
+ var data = -1
+
+ rule.setContent {
+ Box(modifier = Modifier.fillMaxSize()) {
+ RoundToggleButtonWithDefaults(
+ content = {
+ CompositionLocalProvider(
+ LocalContentTestData provides EXPECTED_LOCAL_TEST_DATA
+ ) {
+ data = LocalContentTestData.current
+ }
+ }
+ )
+ }
+ }
+
+ Assert.assertEquals(data, EXPECTED_LOCAL_TEST_DATA)
+ }
+
+ /* Toggle button */
+ @Test
+ fun toggle_button_supports_testTag() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun toggle_button_has_click_action_when_enabled() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+ }
+
+ @Test
+ fun toggle_button_has_click_action_when_disabled() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+ }
+
+ @Test
+ fun toggle_button_is_toggleable() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNode(isToggleable()).assertExists()
+ }
+
+ @Test
+ fun toggle_button_is_correctly_disabled() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsNotEnabled()
+ }
+
+ @Test
+ fun toggle_button_is_correctly_enabled() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+ }
+
+ @Test
+ fun toggle_button_is_on_when_checked() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ checked = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsOn()
+ }
+
+ @Test
+ fun toggle_button_is_off_when_unchecked() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ checked = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsOff()
+ }
+
+ @Test
+ fun toggle_button_responds_to_toggle_on() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ ToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOff()
+ .performClick()
+ .assertIsOn()
+ }
+
+ @Test
+ fun toggle_button_responds_to_toggle_off() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(true) }
+ ToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOn()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun toggle_button_does_not_toggle_when_disabled() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ ToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOff()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun toggle_button_has_role_checkbox() {
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Checkbox
+ )
+ )
+ }
+
+ @Test
+ fun toggle_button_displays_label_content() {
+ val textContent = "abc"
+
+ rule.setContent {
+ ToggleButtonWithDefaults(
+ checked = true,
+ onCheckedChange = {},
+ label = {
+ TestText(text = textContent)
+ }
+ )
+ }
+
+ rule.onNodeWithText(textContent).assertExists()
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun toggle_button_allows_checked_background_color_override() =
+ verifyToggleButtonBackgroundColor(
+ checked = true,
+ enabled = true,
+ expectedColor = CHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun toggle_button_allows_unchecked_background_color_override() =
+ verifyToggleButtonBackgroundColor(
+ checked = false,
+ enabled = true,
+ expectedColor = UNCHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun toggle_button_allows_disabled_checked_background_color_override() =
+ verifyToggleButtonBackgroundColor(
+ checked = true,
+ enabled = false,
+ expectedColor = DISABLED_CHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun toggle_button_allows_disabled_unchecked_background_color_override() =
+ verifyToggleButtonBackgroundColor(
+ checked = false,
+ enabled = false,
+ expectedColor = DISABLED_UNCHECKED_COLOR
+ )
+
+ /* Split toggle buttons */
+
+ @Test
+ fun split_button_supports_testTag() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun split_button_has_click_action_when_enabled() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+ }
+
+ @Test
+ fun split_button_has_click_action_when_disabled() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+ }
+
+ @Test
+ fun split_button_is_toggleable() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNode(isToggleable()).assertExists()
+ }
+
+ @Test
+ fun split_button_is_clickable() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+ }
+
+ @Test
+ fun split_button_is_correctly_enabled() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+ }
+
+ @Test
+ fun split_button_is_correctly_disabled() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertIsNotEnabled()
+ }
+
+ @Test
+ fun split_button_is_off_when_unchecked() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ checked = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOff()
+ }
+
+ @Test
+ fun split_button_is_on_when_checked() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ checked = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOn()
+ }
+
+ @Test
+ fun split_button_responds_to_toggle_on() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .onChildAt(1)
+ .assertIsOff()
+ .performClick()
+ .assertIsOn()
+ }
+
+ @Test
+ fun split_button_responds_to_toggle_off() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(true) }
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .onChildAt(1)
+ .assertIsOn()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun split_button_does_not_toggle_when_disabled() {
+ rule.setContent {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .onChildAt(1)
+ .assertIsOff()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun split_button_has_roles_button_and_checkbox() {
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Button
+ )
+ )
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(1)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Checkbox
+ )
+ )
+ }
+
+ @Test
+ fun split_button_displays_label_content() {
+ val textContent = "abc"
+
+ rule.setContent {
+ SplitToggleButtonWithDefaults(
+ checked = true,
+ onCheckedChange = {},
+ label = {
+ TestText(text = textContent)
+ }
+ )
+ }
+
+ rule.onNodeWithText(textContent).assertExists()
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun split_toggle_button_allows_checked_background_color_override() =
+ verifySplitToggleButtonBackgroundColor(
+ checked = true,
+ enabled = true,
+ expectedColor = CHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun split_toggle_button_allows_unchecked_background_color_override() =
+ verifySplitToggleButtonBackgroundColor(
+ checked = false,
+ enabled = true,
+ expectedColor = UNCHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun split_toggle_button_allows_disabled_checked_background_color_override() =
+ verifySplitToggleButtonBackgroundColor(
+ checked = true,
+ enabled = false,
+ expectedColor = DISABLED_CHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun split_toggle_button_allows_disabled_unchecked_background_color_override() =
+ verifySplitToggleButtonBackgroundColor(
+ checked = false,
+ enabled = false,
+ expectedColor = DISABLED_UNCHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun verifyToggleButtonBackgroundColor(
+ checked: Boolean,
+ enabled: Boolean,
+ expectedColor: Color
+ ) {
+ rule.setContent {
+ Box(modifier = Modifier.fillMaxSize()) {
+ ToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = {},
+ enabled = enabled,
+ background = { isEnabled, isChecked ->
+ val color =
+ if (isEnabled) {
+ if (isChecked) CHECKED_COLOR else UNCHECKED_COLOR
+ } else {
+ if (isChecked) DISABLED_CHECKED_COLOR else DISABLED_UNCHECKED_COLOR
+ }
+
+ Modifier.background(color)
+ },
+ modifier = Modifier.testTag(TEST_TAG),
+ )
+ }
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertContainsColor(expectedColor)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun verifySplitToggleButtonBackgroundColor(
+ checked: Boolean,
+ enabled: Boolean,
+ expectedColor: Color
+ ) {
+ rule.setContent {
+ Box(modifier = Modifier.fillMaxSize()) {
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = {},
+ enabled = enabled,
+ backgroundColor = { isEnabled, isChecked ->
+ rememberUpdatedState(
+ if (isEnabled) {
+ if (isChecked) CHECKED_COLOR else UNCHECKED_COLOR
+ } else {
+ if (isChecked) DISABLED_CHECKED_COLOR else DISABLED_UNCHECKED_COLOR
+ }
+ )
+ },
+ modifier = Modifier.testTag(TEST_TAG),
+ )
+ }
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertContainsColor(expectedColor)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun verifyToggleButtonColors(
+ enabled: Boolean,
+ checked: Boolean,
+ backgroundColor: @Composable (Boolean, Boolean) -> State<Color>,
+ borderColor: @Composable (Boolean, Boolean) -> State<Color>,
+ expectedBackgroundColor: Color,
+ expectedBorderColor: Color,
+ backgroundThreshold: Float = 50.0f,
+ borderThreshold: Float = 1.0f,
+ ) {
+ val testBackground = Color.White
+ val expectedColor = { color: Color ->
+ if (color != Color.Transparent)
+ color.compositeOver(testBackground)
+ else
+ testBackground
+ }
+
+ rule.setContent {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(testBackground)
+ ) {
+ val actualBorderColor = borderColor(enabled, checked).value
+ val border = remember { mutableStateOf(BorderStroke(2.dp, actualBorderColor)) }
+ RoundToggleButtonWithDefaults(
+ backgroundColor = backgroundColor,
+ border = { _, _ -> return@RoundToggleButtonWithDefaults border },
+ enabled = enabled,
+ checked = checked,
+ modifier = Modifier.testTag(TEST_TAG)
+ ) {
+ }
+ }
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertContainsColor(expectedColor(expectedBackgroundColor), backgroundThreshold)
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertContainsColor(expectedColor(expectedBorderColor), borderThreshold)
+ }
+
+ private fun verifyTapSize(
+ expected: Dp,
+ content: @Composable () -> Unit
+ ) {
+ rule.setContent {
+ content()
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .assertTouchHeightIsEqualTo(expected)
+ .assertTouchWidthIsEqualTo(expected)
+ }
+
+ private fun verifyVisibleSize(
+ expected: Dp,
+ content: @Composable () -> Unit
+ ) {
+ rule.setContent {
+ content()
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .assertHeightIsEqualTo(expected)
+ .assertWidthIsEqualTo(expected)
+ }
+}
+
+@Composable
+private fun RoundToggleButtonWithDefaults(
+ modifier: Modifier = Modifier,
+ checked: Boolean = true,
+ onCheckedChange: (Boolean) -> Unit = {},
+ enabled: Boolean = true,
+ backgroundColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color> =
+ { _, _ -> rememberUpdatedState(DEFAULT_SHAPE_COLOR) },
+ border: @Composable (enabled: Boolean, checked: Boolean) -> State<BorderStroke?>? =
+ { _, _ -> null },
+ toggleButtonSize: Dp = 52.dp,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ shape: Shape = CircleShape,
+ content: @Composable BoxScope.() -> Unit = {
+ TestText(text = "Label")
+ }
+) {
+ ToggleButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ modifier = modifier,
+ enabled = enabled,
+ backgroundColor = backgroundColor,
+ border = border,
+ toggleButtonSize = toggleButtonSize,
+ interactionSource = interactionSource,
+ shape = shape,
+ content = content
+ )
+}
+
+@Composable
+private fun ToggleButtonWithDefaults(
+ modifier: Modifier = Modifier,
+ checked: Boolean = true,
+ onCheckedChange: (Boolean) -> Unit = {},
+ label: @Composable RowScope.() -> Unit = {
+ TestText(
+ text = "Label"
+ )
+ },
+ selectionControl: @Composable () -> Unit = { TestImage() },
+ icon: @Composable (BoxScope.() -> Unit)? = null,
+ secondaryLabel: @Composable (RowScope.() -> Unit)? = null,
+ background: @Composable (enabled: Boolean, checked: Boolean) -> Modifier = { _, _ ->
+ Modifier.background(BACKGROUND_COLOR)
+ },
+ enabled: Boolean = true,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ contentPadding: PaddingValues = PaddingValues(
+ start = CHIP_HORIZONTAL_PADDING,
+ top = CHIP_VERTICAL_PADDING,
+ end = CHIP_HORIZONTAL_PADDING,
+ bottom = CHIP_VERTICAL_PADDING
+ ),
+ shape: Shape = CHIP_SHAPE,
+ selectionControlWidth: Dp = 24.dp,
+ selectionControlHeight: Dp = 24.dp
+) = ToggleButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ label = label,
+ selectionControl = selectionControl,
+ modifier = modifier,
+ icon = icon,
+ secondaryLabel = secondaryLabel,
+ background = background,
+ enabled = enabled,
+ interactionSource = interactionSource,
+ contentPadding = contentPadding,
+ shape = shape,
+ selectionControlWidth = selectionControlWidth,
+ selectionControlHeight = selectionControlHeight
+)
+
+@Composable
+private fun SplitToggleButtonWithDefaults(
+ modifier: Modifier = Modifier,
+ checked: Boolean = true,
+ onCheckedChange: (Boolean) -> Unit = {},
+ label: @Composable RowScope.() -> Unit = {
+ TestText(
+ text = "Primary label"
+ )
+ },
+ onClick: () -> Unit = {},
+ selectionControl: @Composable BoxScope.() -> Unit = { TestImage() },
+ secondaryLabel: @Composable (RowScope.() -> Unit)? = null,
+ backgroundColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color> = { _, _ ->
+ remember { mutableStateOf(BACKGROUND_COLOR) }
+ },
+ splitBackgroundColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color> =
+ { _, _ ->
+ remember { mutableStateOf(SPLIT_BACKGROUND_OVERLAY) }
+ },
+ enabled: Boolean = true,
+ checkedInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ clickInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ contentPadding: PaddingValues = PaddingValues(
+ start = CHIP_HORIZONTAL_PADDING,
+ top = CHIP_VERTICAL_PADDING,
+ end = CHIP_HORIZONTAL_PADDING,
+ bottom = CHIP_VERTICAL_PADDING
+ ),
+ shape: Shape = CHIP_SHAPE
+) = SplitToggleButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ label = label,
+ onClick = onClick,
+ selectionControl = selectionControl,
+ modifier = modifier,
+ secondaryLabel = secondaryLabel,
+ backgroundColor = backgroundColor,
+ splitBackgroundColor = splitBackgroundColor,
+ enabled = enabled,
+ checkedInteractionSource = checkedInteractionSource,
+ clickInteractionSource = clickInteractionSource,
+ contentPadding = contentPadding,
+ shape = shape
+)
+
+private val CHIP_HORIZONTAL_PADDING = 14.dp
+private val CHIP_VERTICAL_PADDING = 6.dp
+private val CHIP_SHAPE = RoundedCornerShape(corner = CornerSize(50))
+
+private val CHECKED_COLOR = Color(0xFFA020F0)
+private val UNCHECKED_COLOR = Color(0xFFFFA500)
+private val DISABLED_CHECKED_COLOR = Color(0xFFA56D61)
+private val DISABLED_UNCHECKED_COLOR = Color(0xFF904332)
+private val BACKGROUND_COLOR = Color.Blue
+private val SPLIT_BACKGROUND_OVERLAY = Color.Red
diff --git a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt
index 27f4bc0..56222e7 100644
--- a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt
+++ b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/SelectionControls.kt
@@ -96,6 +96,8 @@
val progress = animateProgress(
transition = transition, label = "Checkbox", animationSpec = progressAnimationSpec
)
+ val isRtl = isLayoutDirectionRtl()
+ val startXOffset = if (isRtl) 0.dp else width - height
// For Checkbox, the color and alpha animations have the same duration and easing,
// so we don't need to explicitly animate alpha.
@@ -119,17 +121,17 @@
.drawWithCache
{
onDrawWithContent {
- drawBox(this, boxColorState.value, progress.value)
+ drawBox(this, boxColorState.value, progress.value, isRtl)
if (targetState == SelectionStage.Checked) {
// Passing startXOffset as we want checkbox to be aligned to the end of the canvas.
- drawTick(checkmarkColorState.value, progress.value, width - height, enabled)
+ drawTick(checkmarkColorState.value, progress.value, startXOffset, enabled)
} else {
// Passing startXOffset as we want checkbox to be aligned to the end of the canvas.
eraseTick(
checkmarkColorState.value,
progress.value,
- width - height,
+ startXOffset,
enabled
)
}
@@ -274,6 +276,7 @@
) {
val targetState = if (selected) SelectionStage.Checked else SelectionStage.Unchecked
val transition = updateTransition(targetState)
+ val isRtl = isLayoutDirectionRtl()
val radioRingColor = ringColor(enabled, selected)
val radioDotColor = dotColor(enabled, selected)
@@ -307,8 +310,9 @@
)
.drawWithCache
{
- // Aligning the radio to the right.
- val startXOffsetPx = (width - height).toPx() / 2
+ // Aligning the radio to the end.
+ val startXOffsetPx = if (isRtl) -(width - height).toPx() / 2 else
+ (width - height).toPx() / 2
// Outer circle has a constant radius.
onDrawWithContent {
val circleCenter = Offset(center.x + startXOffsetPx, center.y)
@@ -368,7 +372,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
fun interface FunctionDrawBox {
- operator fun invoke(drawScope: DrawScope, color: Color, progress: Float)
+ operator fun invoke(drawScope: DrawScope, color: Color, progress: Float, isRtl: Boolean)
}
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@@ -466,7 +470,7 @@
tickColor: Color,
tickProgress: Float,
startXOffset: Dp,
- enabled: Boolean
+ enabled: Boolean,
) {
// Using tickProgress animating from zero to TICK_TOTAL_LENGTH,
// rotate the tick as we draw from 15 degrees to zero.
diff --git a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/ToggleButton.kt b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/ToggleButton.kt
index 0047502..91d6680 100644
--- a/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/ToggleButton.kt
+++ b/wear/compose/compose-material-core/src/main/java/androidx/wear/compose/materialcore/ToggleButton.kt
@@ -20,11 +20,26 @@
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.calculateEndPadding
+import androidx.compose.foundation.layout.calculateStartPadding
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
@@ -32,12 +47,15 @@
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
/**
* Wear Material [ToggleButton] that offers a single slot to take any content
@@ -112,3 +130,291 @@
content = content
)
}
+
+/**
+ * The [ToggleButton] offers four slots and a specific layout for an icon, a
+ * label, a secondaryLabel and selection control. The icon and secondaryLabel are optional.
+ * The items are laid out in a row with the optional icon at the start, a column containing the two
+ * label slots in the middle and a slot for the selection control at the end.
+ *
+ * ToggleButtons can be enabled or disabled. A disabled ToggleButton will not respond to
+ * click events.
+ *
+ * @param checked Boolean flag indicating whether this button is currently checked.
+ * @param onCheckedChange Callback to be invoked when this buttons checked/selected status is
+ * @param label A slot for providing the ToggleButton's main label. The contents are expected
+ * to be text which is "start" aligned.
+ * @param selectionControl A slot for providing the ToggleButton's selection controls(s).
+ * Three built-in types of selection control are supported.
+ * @param modifier Modifier to be applied to the ToggleButton. Pass Modifier.height(height)
+ * or Modifier.defaultMinSize(minHeight = minHeight) to set a fixed height or a minimum height
+ * for the button respectively.
+ * @param icon An optional slot for providing an icon to indicate the purpose of the ToggleButton.
+ * @param secondaryLabel A slot for providing the ToggleButton's secondary label.
+ * The contents are expected to be text which is "start" aligned if there is an icon preset and
+ * "start" or "center" aligned if not. label and secondaryLabel contents should be
+ * consistently aligned.
+ * @param background Composable lambda to set the background of the toggle button.
+ * This expects to return Modifier.paint or Modifier.background for the background treatment.
+ * @param enabled Controls the enabled state of the ToggleButton. When `false`,
+ * this ToggleButton will not be clickable
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this ToggleButton's "toggleable" tap area. You can create and pass in
+ * your own remembered [MutableInteractionSource] if you want to observe [Interaction]s
+ * and customize the appearance / behavior of this ToggleButton in different [Interaction]s.
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content
+ * @param shape Defines the ToggleButton's shape. It is strongly recommended to use the
+ * default as this shape is a key characteristic of the Wear Material Theme
+ * @param selectionControlWidth Width for the selection control.
+ * @param selectionControlHeight Height for the selection control.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@Composable
+fun ToggleButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ label: @Composable RowScope.() -> Unit,
+ selectionControl: @Composable () -> Unit,
+ modifier: Modifier,
+ icon: @Composable (BoxScope.() -> Unit)?,
+ secondaryLabel: @Composable (RowScope.() -> Unit)?,
+ background: @Composable (enabled: Boolean, checked: Boolean) -> Modifier,
+ enabled: Boolean,
+ interactionSource: MutableInteractionSource,
+ contentPadding: PaddingValues,
+ shape: Shape,
+ selectionControlWidth: Dp,
+ selectionControlHeight: Dp
+) {
+ Row(
+ modifier = modifier
+ .clip(shape = shape)
+ .width(IntrinsicSize.Max)
+ .then(background(enabled, checked))
+ .toggleable(
+ enabled = enabled,
+ value = checked,
+ onValueChange = onCheckedChange,
+ indication = rememberRipple(),
+ interactionSource = interactionSource
+ )
+ .semantics {
+ role = Role.Checkbox
+ }
+ .padding(contentPadding),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ ToggleButtonIcon(content = icon)
+ Labels(
+ label = label,
+ secondaryLabel = secondaryLabel
+ )
+ Spacer(
+ modifier = Modifier.size(
+ SELECTION_CONTROL_SPACING
+ )
+ )
+ SelectionControl(
+ width = selectionControlWidth,
+ height = selectionControlHeight,
+ content = selectionControl
+ )
+ }
+}
+
+/**
+ * The [SplitToggleButton] offers three slots and a specific layout for a label,
+ * secondaryLabel and selection control. The secondaryLabel is optional. The items are laid out
+ * with a column containing the two label slots and a slot for the selection control at the
+ * end.
+ *
+ * A [SplitToggleButton] has two tappable areas, one tap area for the labels and another for the
+ * selection control. The [onClick] listener will be associated with the main body of the
+ * SplitToggleButton with the [onCheckedChange] listener associated with the selection
+ * control area only.
+ *
+ * For a SplitToggleButton the background of the tappable background area behind
+ * the selection control will have a visual effect applied to provide a "divider" between the two
+ * tappable areas.
+ *
+ * SplitToggleButton can be enabled or disabled. A disabled SplitToggleButton will not
+ * respond to click events.
+ *
+ * @param checked Boolean flag indicating whether this button is currently checked.
+ * @param onCheckedChange Callback to be invoked when this buttons checked/selected status is
+ * changed.
+ * @param label A slot for providing the SplitToggleButton's main label.
+ * The contents are expected to be text which is "start" aligned.
+ * @param onClick Click listener called when the user clicks the main body of the
+ * SplitToggleButton, the area behind the labels.
+ * @param selectionControl A slot for providing the SplitToggleButton's selection controls(s).
+ * @param modifier Modifier to be applied to the SplitToggleButton
+ * @param secondaryLabel A slot for providing the SplitToggleButton's secondary label.
+ * The contents are expected to be "start" or "center" aligned. label and secondaryLabel
+ * contents should be consistently aligned.
+ * @param backgroundColor Composable lambda from which the backgroundColor will be obtained.
+ * @param splitBackgroundColor Composable lambda from which the splitBackgroundOverlay will be
+ * obtained.
+ * @param enabled Controls the enabled state of the SplitToggleButton. When `false`,
+ * this SplitToggleButton will not be clickable
+ * @param checkedInteractionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this SplitToggleButton's "toggleable" tap area. You can create and pass
+ * in your own remembered [MutableInteractionSource] if you want to observe [Interaction]s and
+ * customize the appearance / behavior of this SplitToggleButton in different [Interaction]s.
+ * @param clickInteractionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this SplitToggleButton's "clickable" tap area. You can create and pass
+ * in your own remembered [MutableInteractionSource] if you want to observe [Interaction]s and
+ * customize the appearance / behavior of this SplitToggleButton in different [Interaction]s.
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content
+ * @param shape Defines the SplitToggleButton's shape. It is strongly recommended to use the
+ * default as this shape is a key characteristic of the Wear Material Theme
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@Composable
+fun SplitToggleButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ label: @Composable RowScope.() -> Unit,
+ onClick: () -> Unit,
+ selectionControl: @Composable BoxScope.() -> Unit,
+ modifier: Modifier,
+ secondaryLabel: @Composable (RowScope.() -> Unit)?,
+ backgroundColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color>,
+ splitBackgroundColor: @Composable (enabled: Boolean, checked: Boolean) -> State<Color>,
+ enabled: Boolean,
+ checkedInteractionSource: MutableInteractionSource,
+ clickInteractionSource: MutableInteractionSource,
+ contentPadding: PaddingValues,
+ shape: Shape
+) {
+ val (startPadding, endPadding) = contentPadding.splitHorizontally()
+
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = modifier
+ .width(IntrinsicSize.Max)
+ .clip(shape = shape)
+ .background(backgroundColor(enabled, checked).value)
+ ) {
+ Row(
+ modifier = Modifier
+ .clickable(
+ enabled = enabled,
+ onClick = onClick,
+ indication = rememberRipple(),
+ interactionSource = clickInteractionSource,
+ )
+ .semantics {
+ role = Role.Button
+ }
+ .fillMaxHeight()
+ .then(startPadding)
+ .weight(1.0f),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Labels(
+ label = label,
+ secondaryLabel = secondaryLabel,
+ )
+ Spacer(
+ modifier = Modifier
+ .size(SELECTION_CONTROL_SPACING)
+ )
+ }
+
+ val splitBackground = splitBackgroundColor(
+ enabled,
+ checked,
+ ).value
+
+ Box(
+ modifier = Modifier
+ .toggleable(
+ enabled = enabled,
+ value = checked,
+ onValueChange = onCheckedChange,
+ indication = rememberRipple(),
+ interactionSource = checkedInteractionSource
+ )
+ .semantics {
+ role = Role.Checkbox
+ }
+ .fillMaxHeight()
+ .drawWithCache {
+ onDrawWithContent {
+ drawRect(color = splitBackground)
+ drawContent()
+ }
+ }
+ .align(Alignment.CenterVertically)
+ .width(52.dp)
+ .wrapContentHeight(align = Alignment.CenterVertically)
+ .wrapContentWidth(align = Alignment.End)
+ .then(endPadding),
+ content = selectionControl
+ )
+ }
+}
+
+@Composable
+private fun ToggleButtonIcon(
+ content: @Composable (BoxScope.() -> Unit)? = null
+) {
+ if (content != null) {
+ Box(
+ modifier = Modifier.wrapContentSize(align = Alignment.Center),
+ content = content
+ )
+ Spacer(modifier = Modifier.size(ICON_SPACING))
+ }
+}
+
+@Composable
+private fun RowScope.Labels(
+ label: @Composable RowScope.() -> Unit,
+ secondaryLabel: @Composable (RowScope.() -> Unit)?
+) {
+ Column(modifier = Modifier.weight(1.0f)) {
+ Row(content = label)
+ if (secondaryLabel != null) {
+ Row(content = secondaryLabel)
+ }
+ }
+}
+
+@Composable
+private fun RowScope.SelectionControl(
+ width: Dp,
+ height: Dp,
+ content: @Composable () -> Unit
+) {
+ Box(
+ modifier = Modifier
+ .align(Alignment.CenterVertically)
+ .size(width = width, height = height)
+ .wrapContentWidth(align = Alignment.End),
+ ) {
+ content()
+ }
+}
+
+@Composable
+private fun PaddingValues.splitHorizontally() =
+ Modifier.padding(
+ start = calculateStartPadding(LocalLayoutDirection.current),
+ end = 0.dp,
+ top = calculateTopPadding(),
+ bottom = calculateBottomPadding()
+ ) to Modifier.padding(
+ start = 0.dp,
+ end = calculateEndPadding(
+ layoutDirection = LocalLayoutDirection.current
+ ),
+ top = calculateTopPadding(),
+ bottom = calculateBottomPadding()
+ )
+
+private val SELECTION_CONTROL_SPACING = 4.dp
+private val ICON_SPACING = 6.dp
diff --git a/wear/compose/compose-material/api/current.txt b/wear/compose/compose-material/api/current.txt
index c1b45d8..099285e 100644
--- a/wear/compose/compose-material/api/current.txt
+++ b/wear/compose/compose-material/api/current.txt
@@ -207,9 +207,9 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class FractionalThreshold implements androidx.wear.compose.material.ThresholdConfig {
- ctor public FractionalThreshold(float fraction);
+ ctor public FractionalThreshold(@FloatRange(from=0.0, to=1.0) float fraction);
method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
- method public androidx.wear.compose.material.FractionalThreshold copy(float fraction);
+ method public androidx.wear.compose.material.FractionalThreshold copy(@FloatRange(from=0.0, to=1.0) float fraction);
}
public final class HorizontalPageIndicatorKt {
@@ -326,10 +326,10 @@
}
public final class PickerKt {
- method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
- method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
- method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
- method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerState rememberPickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
}
@@ -412,10 +412,10 @@
}
@androidx.compose.runtime.Stable public interface PositionIndicatorState {
- method public float getPositionFraction();
- method public float sizeFraction(float scrollableContainerSizePx);
- method public int visibility(float scrollableContainerSizePx);
- property public abstract float positionFraction;
+ method @FloatRange(from=0.0, to=1.0) public float getPositionFraction();
+ method @FloatRange(from=0.0, to=1.0) public float sizeFraction(@FloatRange(from=0.0) float scrollableContainerSizePx);
+ method public int visibility(@FloatRange(from=0.0) float scrollableContainerSizePx);
+ property @FloatRange(from=0.0, to=1.0) public abstract float positionFraction;
}
@kotlin.jvm.JvmInline public final value class PositionIndicatorVisibility {
@@ -441,7 +441,7 @@
public final class ProgressIndicatorKt {
method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
- method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
+ method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
}
@androidx.compose.runtime.Stable public interface RadioButtonColors {
@@ -455,7 +455,7 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class ResistanceConfig {
- ctor public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
+ ctor public ResistanceConfig(@FloatRange(from=0.0, fromInclusive=false) float basis, optional @FloatRange(from=0.0) float factorAtMin, optional @FloatRange(from=0.0) float factorAtMax);
method public float computeResistance(float overflow);
method public float getBasis();
method public float getFactorAtMax();
@@ -514,9 +514,9 @@
}
@Deprecated @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
- method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
- method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
- method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+ method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
}
@Deprecated public sealed interface ScalingLazyListLayoutInfo {
@@ -581,20 +581,20 @@
}
@Deprecated @androidx.compose.runtime.Stable public interface ScalingParams {
- method @Deprecated public float getEdgeAlpha();
- method @Deprecated public float getEdgeScale();
- method @Deprecated public float getMaxElementHeight();
- method @Deprecated public float getMaxTransitionArea();
- method @Deprecated public float getMinElementHeight();
- method @Deprecated public float getMinTransitionArea();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
method @Deprecated public androidx.compose.animation.core.Easing getScaleInterpolator();
method @Deprecated public int resolveViewportVerticalOffset(long viewportConstraints);
- property @Deprecated public abstract float edgeAlpha;
- property @Deprecated public abstract float edgeScale;
- property @Deprecated public abstract float maxElementHeight;
- property @Deprecated public abstract float maxTransitionArea;
- property @Deprecated public abstract float minElementHeight;
- property @Deprecated public abstract float minTransitionArea;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
property @Deprecated public abstract androidx.compose.animation.core.Easing scaleInterpolator;
}
@@ -645,7 +645,7 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeProgress<T> {
- ctor public SwipeProgress(T from, T to, float fraction);
+ ctor public SwipeProgress(T from, T to, @FloatRange(from=0.0, to=1.0) float fraction);
method public float getFraction();
method public T getFrom();
method public T getTo();
@@ -694,6 +694,55 @@
enum_constant public static final androidx.wear.compose.material.SwipeToDismissValue Dismissed;
}
+ @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealAction {
+ ctor public SwipeToRevealAction(kotlin.jvm.functions.Function0<kotlin.Unit>? icon, kotlin.jvm.functions.Function0<kotlin.Unit>? label, androidx.compose.ui.Modifier modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getIcon();
+ method public androidx.compose.foundation.interaction.MutableInteractionSource getInteractionSource();
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getLabel();
+ method public androidx.compose.ui.Modifier getModifier();
+ method public kotlin.jvm.functions.Function0<kotlin.Unit> getOnClick();
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? icon;
+ property public final androidx.compose.foundation.interaction.MutableInteractionSource interactionSource;
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? label;
+ property public final androidx.compose.ui.Modifier modifier;
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit> onClick;
+ }
+
+ @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealActionColors {
+ ctor public SwipeToRevealActionColors(long actionBackgroundColor, long actionContentColor, long additionalActionBackgroundColor, long additionalActionContentColor, long undoActionBackgroundColor, long undoActionContentColor);
+ method public long getActionBackgroundColor();
+ method public long getActionContentColor();
+ method public long getAdditionalActionBackgroundColor();
+ method public long getAdditionalActionContentColor();
+ method public long getUndoActionBackgroundColor();
+ method public long getUndoActionContentColor();
+ property public final long actionBackgroundColor;
+ property public final long actionContentColor;
+ property public final long additionalActionBackgroundColor;
+ property public final long additionalActionContentColor;
+ property public final long undoActionBackgroundColor;
+ property public final long undoActionContentColor;
+ }
+
+ @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealDefaults {
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction action(kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealActionColors actionColors(optional long actionBackgroundColor, optional long actionContentColor, optional long additionalActionBackgroundColor, optional long additionalActionContentColor, optional long undoActionBackgroundColor, optional long undoActionContentColor);
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction additionalAction(kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ method public androidx.compose.foundation.shape.RoundedCornerShape getCardActionShape();
+ method public androidx.compose.ui.graphics.vector.ImageVector getDelete();
+ method public androidx.compose.ui.graphics.vector.ImageVector getMoreOptions();
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction undoAction(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ property public final androidx.compose.foundation.shape.RoundedCornerShape CardActionShape;
+ property public final androidx.compose.ui.graphics.vector.ImageVector Delete;
+ property public final androidx.compose.ui.graphics.vector.ImageVector MoreOptions;
+ field public static final androidx.wear.compose.material.SwipeToRevealDefaults INSTANCE;
+ }
+
+ public final class SwipeToRevealKt {
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealCard(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealChip(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
@SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeableDefaults {
method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
method public float getVelocityThreshold();
diff --git a/wear/compose/compose-material/api/restricted_current.txt b/wear/compose/compose-material/api/restricted_current.txt
index c1b45d8..099285e 100644
--- a/wear/compose/compose-material/api/restricted_current.txt
+++ b/wear/compose/compose-material/api/restricted_current.txt
@@ -207,9 +207,9 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class FractionalThreshold implements androidx.wear.compose.material.ThresholdConfig {
- ctor public FractionalThreshold(float fraction);
+ ctor public FractionalThreshold(@FloatRange(from=0.0, to=1.0) float fraction);
method public float computeThreshold(androidx.compose.ui.unit.Density, float fromValue, float toValue);
- method public androidx.wear.compose.material.FractionalThreshold copy(float fraction);
+ method public androidx.wear.compose.material.FractionalThreshold copy(@FloatRange(from=0.0, to=1.0) float fraction);
}
public final class HorizontalPageIndicatorKt {
@@ -326,10 +326,10 @@
}
public final class PickerKt {
- method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
- method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
- method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
- method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.foundation.lazy.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, optional boolean userScrollEnabled, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
+ method @Deprecated @androidx.compose.runtime.Composable public static void Picker(androidx.wear.compose.material.PickerState state, String? contentDescription, optional androidx.compose.ui.Modifier modifier, optional boolean readOnly, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? readOnlyLabel, optional kotlin.jvm.functions.Function0<kotlin.Unit> onSelected, optional androidx.wear.compose.material.ScalingParams scalingParams, optional float separation, optional @FloatRange(from=0.0, to=0.5) float gradientRatio, optional long gradientColor, optional androidx.compose.foundation.gestures.FlingBehavior flingBehavior, kotlin.jvm.functions.Function2<? super androidx.wear.compose.material.PickerScope,? super java.lang.Integer,kotlin.Unit> option);
method @androidx.compose.runtime.Composable public static androidx.wear.compose.material.PickerState rememberPickerState(int initialNumberOfOptions, optional int initiallySelectedOption, optional boolean repeatItems);
}
@@ -412,10 +412,10 @@
}
@androidx.compose.runtime.Stable public interface PositionIndicatorState {
- method public float getPositionFraction();
- method public float sizeFraction(float scrollableContainerSizePx);
- method public int visibility(float scrollableContainerSizePx);
- property public abstract float positionFraction;
+ method @FloatRange(from=0.0, to=1.0) public float getPositionFraction();
+ method @FloatRange(from=0.0, to=1.0) public float sizeFraction(@FloatRange(from=0.0) float scrollableContainerSizePx);
+ method public int visibility(@FloatRange(from=0.0) float scrollableContainerSizePx);
+ property @FloatRange(from=0.0, to=1.0) public abstract float positionFraction;
}
@kotlin.jvm.JvmInline public final value class PositionIndicatorVisibility {
@@ -441,7 +441,7 @@
public final class ProgressIndicatorKt {
method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
- method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
+ method @androidx.compose.runtime.Composable public static void CircularProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, optional androidx.compose.ui.Modifier modifier, optional float startAngle, optional float endAngle, optional long indicatorColor, optional long trackColor, optional float strokeWidth);
}
@androidx.compose.runtime.Stable public interface RadioButtonColors {
@@ -455,7 +455,7 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class ResistanceConfig {
- ctor public ResistanceConfig(float basis, optional float factorAtMin, optional float factorAtMax);
+ ctor public ResistanceConfig(@FloatRange(from=0.0, fromInclusive=false) float basis, optional @FloatRange(from=0.0) float factorAtMin, optional @FloatRange(from=0.0) float factorAtMax);
method public float computeResistance(float overflow);
method public float getBasis();
method public float getFactorAtMax();
@@ -514,9 +514,9 @@
}
@Deprecated @androidx.compose.runtime.Stable @androidx.wear.compose.material.ScalingLazyScopeMarker public sealed interface ScalingLazyListItemScope {
- method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional float fraction);
- method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional float fraction);
- method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional float fraction);
+ method @Deprecated public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method @Deprecated public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
+ method @Deprecated public androidx.compose.ui.Modifier fillParentMaxWidth(androidx.compose.ui.Modifier, optional @FloatRange(from=0.0, to=1.0) float fraction);
}
@Deprecated public sealed interface ScalingLazyListLayoutInfo {
@@ -581,20 +581,20 @@
}
@Deprecated @androidx.compose.runtime.Stable public interface ScalingParams {
- method @Deprecated public float getEdgeAlpha();
- method @Deprecated public float getEdgeScale();
- method @Deprecated public float getMaxElementHeight();
- method @Deprecated public float getMaxTransitionArea();
- method @Deprecated public float getMinElementHeight();
- method @Deprecated public float getMinTransitionArea();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeAlpha();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getEdgeScale();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxElementHeight();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMaxTransitionArea();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinElementHeight();
+ method @Deprecated @FloatRange(from=0.0, to=1.0) public float getMinTransitionArea();
method @Deprecated public androidx.compose.animation.core.Easing getScaleInterpolator();
method @Deprecated public int resolveViewportVerticalOffset(long viewportConstraints);
- property @Deprecated public abstract float edgeAlpha;
- property @Deprecated public abstract float edgeScale;
- property @Deprecated public abstract float maxElementHeight;
- property @Deprecated public abstract float maxTransitionArea;
- property @Deprecated public abstract float minElementHeight;
- property @Deprecated public abstract float minTransitionArea;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeAlpha;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float edgeScale;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxElementHeight;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float maxTransitionArea;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minElementHeight;
+ property @Deprecated @FloatRange(from=0.0, to=1.0) public abstract float minTransitionArea;
property @Deprecated public abstract androidx.compose.animation.core.Easing scaleInterpolator;
}
@@ -645,7 +645,7 @@
}
@SuppressCompatibility @androidx.compose.runtime.Immutable @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeProgress<T> {
- ctor public SwipeProgress(T from, T to, float fraction);
+ ctor public SwipeProgress(T from, T to, @FloatRange(from=0.0, to=1.0) float fraction);
method public float getFraction();
method public T getFrom();
method public T getTo();
@@ -694,6 +694,55 @@
enum_constant public static final androidx.wear.compose.material.SwipeToDismissValue Dismissed;
}
+ @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealAction {
+ ctor public SwipeToRevealAction(kotlin.jvm.functions.Function0<kotlin.Unit>? icon, kotlin.jvm.functions.Function0<kotlin.Unit>? label, androidx.compose.ui.Modifier modifier, androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getIcon();
+ method public androidx.compose.foundation.interaction.MutableInteractionSource getInteractionSource();
+ method public kotlin.jvm.functions.Function0<kotlin.Unit>? getLabel();
+ method public androidx.compose.ui.Modifier getModifier();
+ method public kotlin.jvm.functions.Function0<kotlin.Unit> getOnClick();
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? icon;
+ property public final androidx.compose.foundation.interaction.MutableInteractionSource interactionSource;
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit>? label;
+ property public final androidx.compose.ui.Modifier modifier;
+ property public final kotlin.jvm.functions.Function0<kotlin.Unit> onClick;
+ }
+
+ @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealActionColors {
+ ctor public SwipeToRevealActionColors(long actionBackgroundColor, long actionContentColor, long additionalActionBackgroundColor, long additionalActionContentColor, long undoActionBackgroundColor, long undoActionContentColor);
+ method public long getActionBackgroundColor();
+ method public long getActionContentColor();
+ method public long getAdditionalActionBackgroundColor();
+ method public long getAdditionalActionContentColor();
+ method public long getUndoActionBackgroundColor();
+ method public long getUndoActionContentColor();
+ property public final long actionBackgroundColor;
+ property public final long actionContentColor;
+ property public final long additionalActionBackgroundColor;
+ property public final long additionalActionContentColor;
+ property public final long undoActionBackgroundColor;
+ property public final long undoActionContentColor;
+ }
+
+ @SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeToRevealDefaults {
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction action(kotlin.jvm.functions.Function0<kotlin.Unit> icon, kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealActionColors actionColors(optional long actionBackgroundColor, optional long actionContentColor, optional long additionalActionBackgroundColor, optional long additionalActionContentColor, optional long undoActionBackgroundColor, optional long undoActionContentColor);
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction additionalAction(kotlin.jvm.functions.Function0<kotlin.Unit> icon, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ method public androidx.compose.foundation.shape.RoundedCornerShape getCardActionShape();
+ method public androidx.compose.ui.graphics.vector.ImageVector getDelete();
+ method public androidx.compose.ui.graphics.vector.ImageVector getMoreOptions();
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material.SwipeToRevealAction undoAction(kotlin.jvm.functions.Function0<kotlin.Unit> label, optional androidx.compose.ui.Modifier modifier, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function0<kotlin.Unit> onClick);
+ property public final androidx.compose.foundation.shape.RoundedCornerShape CardActionShape;
+ property public final androidx.compose.ui.graphics.vector.ImageVector Delete;
+ property public final androidx.compose.ui.graphics.vector.ImageVector MoreOptions;
+ field public static final androidx.wear.compose.material.SwipeToRevealDefaults INSTANCE;
+ }
+
+ public final class SwipeToRevealKt {
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealCard(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ method @SuppressCompatibility @androidx.compose.runtime.Composable @androidx.wear.compose.material.ExperimentalWearMaterialApi public static void SwipeToRevealChip(androidx.wear.compose.material.SwipeToRevealAction action, androidx.wear.compose.foundation.RevealState revealState, optional androidx.compose.ui.Modifier modifier, optional androidx.wear.compose.material.SwipeToRevealAction? additionalAction, optional androidx.wear.compose.material.SwipeToRevealAction? undoAction, optional androidx.wear.compose.material.SwipeToRevealActionColors colors, optional androidx.compose.ui.graphics.Shape shape, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+ }
+
@SuppressCompatibility @androidx.wear.compose.material.ExperimentalWearMaterialApi public final class SwipeableDefaults {
method public androidx.compose.animation.core.SpringSpec<java.lang.Float> getAnimationSpec();
method public float getVelocityThreshold();
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt
index c816e7a..55f9f33 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/PlaceholderTest.kt
@@ -46,7 +46,67 @@
@RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalWearMaterialApi::class)
@Test
- fun placeholder_initially_show_content() {
+ fun placeholder_initially_show_content_when_contentready_true() {
+ lateinit var contentReady: MutableState<Boolean>
+ lateinit var placeholderState: PlaceholderState
+ rule.setContentWithTheme {
+ contentReady = remember { mutableStateOf(true) }
+ placeholderState = rememberPlaceholderState {
+ contentReady.value
+ }
+ }
+
+ // For testing we need to manually manage the frame clock for the placeholder animation
+ placeholderState.initializeTestFrameMillis(PlaceholderStage.ShowContent)
+
+ // Advance placeholder clock without changing the content ready and confirm still in
+ // ShowPlaceholder
+ placeholderState.advanceToNextPlaceholderAnimationLoopAndCheckStage(
+ PlaceholderStage.ShowContent
+ )
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @OptIn(ExperimentalWearMaterialApi::class)
+ @Test
+ fun placeholder_initially_show_placeholder_transitions_correctly() {
+ lateinit var contentReady: MutableState<Boolean>
+ lateinit var placeholderState: PlaceholderState
+ rule.setContentWithTheme {
+ contentReady = remember { mutableStateOf(false) }
+ placeholderState = rememberPlaceholderState {
+ contentReady.value
+ }
+ }
+
+ // For testing we need to manually manage the frame clock for the placeholder animation
+ placeholderState.initializeTestFrameMillis()
+
+ // Advance placeholder clock without changing the content ready and confirm still in
+ // ShowPlaceholder
+ placeholderState.advanceFrameMillisAndCheckState(
+ PLACEHOLDER_SHIMMER_GAP_BETWEEN_ANIMATION_LOOPS_MS,
+ PlaceholderStage.ShowPlaceholder
+ )
+
+ // Change contentReady and confirm that state is now WipeOff
+ contentReady.value = true
+ placeholderState.advanceFrameMillisAndCheckState(
+ 1L,
+ PlaceholderStage.WipeOff
+ )
+
+ // Advance the clock by one cycle and check we have moved to ShowContent
+ placeholderState.advanceFrameMillisAndCheckState(
+ PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
+ PlaceholderStage.ShowContent
+ )
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @OptIn(ExperimentalWearMaterialApi::class)
+ @Test
+ fun placeholder_resets_content_after_show_content_when_contentready_false() {
lateinit var contentReady: MutableState<Boolean>
lateinit var placeholderState: PlaceholderState
rule.setContentWithTheme {
@@ -55,9 +115,7 @@
contentReady.value
}
Chip(
- modifier = Modifier
- .testTag("test-item")
- .fillMaxWidth(),
+ modifier = Modifier.fillMaxWidth(),
content = {},
onClick = {},
colors = ChipDefaults.secondaryChipColors(),
@@ -76,53 +134,10 @@
contentReady.value = false
- // Check that the state does not go to ShowPlaceholder
- placeholderState.advanceToNextPlaceholderAnimationLoopAndCheckStage(
- PlaceholderStage.ShowContent
- )
- }
-
- @RequiresApi(Build.VERSION_CODES.O)
- @OptIn(ExperimentalWearMaterialApi::class)
- @Test
- fun placeholder_initially_show_placeholder_transitions_correctly() {
- var contentReady = false
- lateinit var placeholderState: PlaceholderState
- rule.setContentWithTheme {
- placeholderState = rememberPlaceholderState {
- contentReady
- }
- Chip(
- modifier = Modifier
- .testTag("test-item")
- .fillMaxWidth(),
- content = {},
- onClick = {},
- colors = ChipDefaults.secondaryChipColors(),
- border = ChipDefaults.chipBorder()
- )
- }
-
- // For testing we need to manually manage the frame clock for the placeholder animation
- placeholderState.initializeTestFrameMillis()
-
- // Advance placeholder clock without changing the content ready and confirm still in
- // ShowPlaceholder
+ // Check that the state is set to ResetContent
placeholderState.advanceFrameMillisAndCheckState(
- PLACEHOLDER_SHIMMER_GAP_BETWEEN_ANIMATION_LOOPS_MS,
- PlaceholderStage.ShowPlaceholder)
-
- // Change contentReady and confirm that state is now WipeOff
- contentReady = true
- placeholderState.advanceFrameMillisAndCheckState(
- 0L,
- PlaceholderStage.WipeOff
- )
-
- // Advance the clock by one cycle and check we have moved to ShowContent
- placeholderState.advanceFrameMillisAndCheckState(
- PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
- PlaceholderStage.ShowContent
+ (PLACEHOLDER_RESET_ANIMATION_DURATION * 0.5f).toLong(),
+ PlaceholderStage.ResetContent
)
}
@@ -182,15 +197,18 @@
expectedPlaceholderColor
)
+ // Change contentReady and confirm that state is now WipeOff
contentReady.value = true
+ placeholderState.advanceFrameMillisAndCheckState(
+ 1L,
+ PlaceholderStage.WipeOff
+ )
- // Advance the clock to the next placeholder animation loop and check for wipe-off mode
- placeholderState
- .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.WipeOff)
-
- // Advance the clock to the next placeholder animation loop and check for show content mode
- placeholderState
- .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.ShowContent)
+ // Advance the clock by one cycle and check we have moved to ShowContent
+ placeholderState.advanceFrameMillisAndCheckState(
+ PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
+ PlaceholderStage.ShowContent
+ )
rule.onNodeWithTag("test-item")
.captureToImage()
@@ -239,7 +257,7 @@
// Move the start of the next placeholder shimmer animation loop and them advance the
// clock to show the shimmer.
placeholderState.advanceFrameMillisAndCheckState(
- (PLACEHOLDER_SHIMMER_DURATION_MS * 0.5f).toLong(),
+ (PLACEHOLDER_SHIMMER_DURATION_MS * 0.5f).toLong(),
PlaceholderStage.ShowPlaceholder
)
@@ -249,11 +267,12 @@
.captureToImage()
.assertDoesNotContainColor(expectedBackgroundColor)
- // Prepare to start to wipe off and show contents.
+ // Change contentReady and confirm that state is now WipeOff
contentReady.value = true
-
- placeholderState
- .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.WipeOff)
+ placeholderState.advanceFrameMillisAndCheckState(
+ 1L,
+ PlaceholderStage.WipeOff
+ )
// Check the background color is correct
rule.onNodeWithTag("test-item")
@@ -262,8 +281,11 @@
expectedBackgroundColor, 80f
)
- placeholderState
- .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.ShowContent)
+ // Advance the clock by one cycle and check we have moved to ShowContent
+ placeholderState.advanceFrameMillisAndCheckState(
+ PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
+ PlaceholderStage.ShowContent
+ )
// Check that the shimmer is no longer visible
rule.onNodeWithTag("test-item")
@@ -322,11 +344,12 @@
expectedBackgroundColor
)
- // Prepare to start to wipe off and show contents.
+ // Change contentReady and confirm that state is now WipeOff
contentReady.value = true
-
- placeholderState
- .advanceToNextPlaceholderAnimationLoopAndCheckStage(PlaceholderStage.WipeOff)
+ placeholderState.advanceFrameMillisAndCheckState(
+ 1L,
+ PlaceholderStage.WipeOff
+ )
// Check that placeholder background is still visible
rule.onNodeWithTag("test-item")
@@ -404,10 +427,12 @@
// Trigger move to WipeOff stage
placeholderState.value?.advanceFrameMillisAndCheckState(
- 1, PlaceholderStage.WipeOff)
+ 1, PlaceholderStage.WipeOff
+ )
placeholderState.value?.advanceFrameMillisAndCheckState(
- PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS, PlaceholderStage.ShowContent)
+ PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS, PlaceholderStage.ShowContent
+ )
}
@RequiresApi(Build.VERSION_CODES.O)
@@ -428,6 +453,7 @@
Chip(
modifier = Modifier
.testTag("test-item")
+ .fillMaxWidth()
.placeholderShimmer(placeholderState),
content = {},
onClick = {},
@@ -450,14 +476,16 @@
expectedPlaceholderBackgroundColor
)
+ // Change contentReady and confirm that state is now WipeOff
contentReady.value = true
-
- // Trigger move to WipeOff stage
placeholderState.advanceFrameMillisAndCheckState(
- 1, PlaceholderStage.WipeOff)
+ 1L, PlaceholderStage.WipeOff
+ )
placeholderState.advanceFrameMillisAndCheckState(
- PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS, PlaceholderStage.ShowContent)
+ PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS,
+ PlaceholderStage.ShowContent
+ )
// Check the placeholder background has gone and that we can see the chips background
rule.onNodeWithTag("test-item")
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
index 75181cf..e57f587 100644
--- a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/ScalingLazyListLayoutInfoTest.kt
@@ -134,6 +134,7 @@
scope!!.launch {
state.animateScrollBy(scrollDistance.toFloat())
}
+
rule.runOnIdle {
assertThat(state.centerItemIndex).isEqualTo(1)
assertThat(state.centerItemScrollOffset).isEqualTo(scrollDistance)
@@ -419,6 +420,7 @@
}
}
}
+ rule.mainClock.autoAdvance = false
// TODO(b/210654937): Remove the waitUntil once we no longer need 2 stage initialization
rule.waitUntil { state.initialized.value }
@@ -426,7 +428,8 @@
state.animateScrollBy(localItemSizePx.toFloat() * 10)
}
- rule.waitUntil { !state.isScrollInProgress }
+ rule.mainClock.advanceTimeBy(milliseconds = 1000)
+ assert(!state.isScrollInProgress)
assertThat(state.centerItemIndex).isEqualTo(4)
assertThat(state.centerItemScrollOffset).isEqualTo(0)
@@ -434,7 +437,8 @@
state.animateScrollBy(- localItemSizePx.toFloat() * 10)
}
- rule.waitUntil { !state.isScrollInProgress }
+ rule.mainClock.advanceTimeBy(milliseconds = 1000)
+ assert(!state.isScrollInProgress)
assertThat(state.centerItemIndex).isEqualTo(autoCenterItem)
assertThat(state.centerItemScrollOffset).isEqualTo(0)
}
diff --git a/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealTest.kt b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealTest.kt
new file mode 100644
index 0000000..e30df01
--- /dev/null
+++ b/wear/compose/compose-material/src/androidTest/kotlin/androidx/wear/compose/material/SwipeToRevealTest.kt
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
+import androidx.wear.compose.foundation.RevealState
+import androidx.wear.compose.foundation.RevealValue
+import androidx.wear.compose.foundation.rememberRevealState
+import junit.framework.TestCase.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
+class SwipeToRevealActionTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun supports_testTag_onChip() {
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(modifier = Modifier.testTag(TEST_TAG))
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun supports_testTag_onCard() {
+ rule.setContentWithTheme {
+ swipeToRevealCardDefault(modifier = Modifier.testTag(TEST_TAG))
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun supports_testTag_onContent_onChip() {
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault()
+ }
+
+ rule.onNodeWithTag(CONTENT_TAG).assertExists()
+ }
+
+ @Test
+ fun supports_testTag_onContent_onCard() {
+ rule.setContentWithTheme {
+ swipeToRevealCardDefault()
+ }
+
+ rule.onNodeWithTag(CONTENT_TAG).assertExists()
+ }
+
+ @Test
+ fun whenNotRevealed_actionsDoNotExist_inChip() {
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault()
+ }
+
+ rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+ rule.onNodeWithTag(UNDO_ACTION_TAG).assertDoesNotExist()
+ }
+
+ @Test
+ fun whenNotRevealed_actionsDoNotExist_inCard() {
+ rule.setContentWithTheme {
+ swipeToRevealCardDefault()
+ }
+
+ rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+ rule.onNodeWithTag(UNDO_ACTION_TAG).assertDoesNotExist()
+ }
+
+ @Test
+ fun whenRevealing_actionsExist_inChip() {
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+ )
+ }
+ rule.onNodeWithTag(ACTION_TAG).assertExists()
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertExists()
+ }
+
+ @Test
+ fun whenRevealing_actionsExist_inCard() {
+ rule.setContentWithTheme {
+ swipeToRevealCardDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+ )
+ }
+ rule.onNodeWithTag(ACTION_TAG).assertExists()
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertExists()
+ }
+
+ @Test
+ fun whenRevealed_undoActionExists_inChip() {
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+ )
+ }
+
+ rule.onNodeWithTag(UNDO_ACTION_TAG).assertExists()
+ }
+
+ @Test
+ fun whenRevealed_undoActionExists_inCard() {
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+ )
+ }
+
+ rule.onNodeWithTag(UNDO_ACTION_TAG).assertExists()
+ }
+
+ @Test
+ fun whenRevealed_actionsDoesNotExists_inChip() {
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+ )
+ }
+
+ rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+ }
+
+ @Test
+ fun whenRevealed_actionsDoesNotExists_inCard() {
+ rule.setContentWithTheme {
+ swipeToRevealCardDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+ )
+ }
+
+ rule.onNodeWithTag(ACTION_TAG).assertDoesNotExist()
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).assertDoesNotExist()
+ }
+
+ @Test
+ fun onActionClick_triggersOnClick_forChip() {
+ var clicked = false
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+ action = createAction(
+ onClick = { clicked = true }
+ )
+ )
+ }
+
+ rule.onNodeWithTag(ACTION_TAG).performClick()
+ rule.runOnIdle { assertEquals(true, clicked) }
+ }
+
+ @Test
+ fun onAdditionalActionClick_triggersOnClick_forChip() {
+ var clicked = false
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+ additionalAction = createAdditionalAction(
+ onClick = { clicked = true }
+ )
+ )
+ }
+
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).performClick()
+ rule.runOnIdle { assertEquals(true, clicked) }
+ }
+
+ @Test
+ fun onActionClick_stateChangesToRevealed_forChip() {
+ lateinit var revealState: RevealState
+ rule.setContentWithTheme {
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+ swipeToRevealChipDefault(
+ revealState = revealState,
+ )
+ }
+
+ rule.onNodeWithTag(ACTION_TAG).performClick()
+ rule.runOnIdle { assertEquals(RevealValue.Revealed, revealState.currentValue) }
+ }
+
+ @Test
+ fun onAdditionalActionClick_stateChangesToRevealed_forChip() {
+ lateinit var revealState: RevealState
+ rule.setContentWithTheme {
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+ swipeToRevealChipDefault(
+ revealState = revealState,
+ )
+ }
+
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG).performClick()
+ rule.runOnIdle { assertEquals(RevealValue.Revealed, revealState.currentValue) }
+ }
+
+ @Test
+ fun onUndoActionClick_stateChangesToCovered_forChip() {
+ lateinit var revealState: RevealState
+ rule.setContentWithTheme {
+ revealState = rememberRevealState(initialValue = RevealValue.Revealed)
+ swipeToRevealChipDefault(
+ revealState = revealState,
+ )
+ }
+
+ rule.onNodeWithTag(UNDO_ACTION_TAG).performClick()
+ rule.runOnIdle { assertEquals(RevealValue.Covered, revealState.currentValue) }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun verifyActionColors() {
+ var actionColor = Color.Yellow
+ var additionalActionColor = Color.Green
+ rule.setContentWithTheme {
+ actionColor = MaterialTheme.colors.error
+ additionalActionColor = MaterialTheme.colors.surface
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing)
+ )
+ }
+
+ rule.onNodeWithTag(ACTION_TAG)
+ .captureToImage()
+ .assertContainsColor(actionColor, 50.0f)
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG)
+ .captureToImage()
+ .assertContainsColor(additionalActionColor)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun canOverrideActionColors() {
+ val overrideActionColor = Color.Yellow
+ val overrideAdditionalActionColor = Color.Green
+ rule.setContentWithTheme {
+ swipeToRevealChipDefault(
+ revealState = rememberRevealState(initialValue = RevealValue.Revealing),
+ colors = SwipeToRevealDefaults.actionColors(
+ actionBackgroundColor = overrideActionColor,
+ additionalActionBackgroundColor = overrideAdditionalActionColor
+ )
+ )
+ }
+
+ rule.onNodeWithTag(ACTION_TAG)
+ .captureToImage()
+ .assertContainsColor(overrideActionColor, 50.0f)
+ rule.onNodeWithTag(ADDITIONAL_ACTION_TAG)
+ .captureToImage()
+ .assertContainsColor(overrideAdditionalActionColor, 50.0f)
+ }
+
+ @Composable
+ private fun swipeToRevealChipDefault(
+ modifier: Modifier = Modifier,
+ revealState: RevealState = rememberRevealState(),
+ action: SwipeToRevealAction = createAction(),
+ additionalAction: SwipeToRevealAction = createAdditionalAction(),
+ undoAction: SwipeToRevealAction = createUndoAction(),
+ colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+ content: @Composable () -> Unit = { createContent() }
+ ) {
+ SwipeToRevealChip(
+ modifier = modifier,
+ revealState = revealState,
+ action = action,
+ additionalAction = additionalAction,
+ undoAction = undoAction,
+ colors = colors,
+ content = content
+ )
+ }
+
+ @Composable
+ private fun swipeToRevealCardDefault(
+ modifier: Modifier = Modifier,
+ revealState: RevealState = rememberRevealState(),
+ action: SwipeToRevealAction = createAction(),
+ additionalAction: SwipeToRevealAction = createAdditionalAction(),
+ undoAction: SwipeToRevealAction = createUndoAction(),
+ colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+ content: @Composable () -> Unit = { createContent() }
+ ) {
+ SwipeToRevealCard(
+ modifier = modifier,
+ revealState = revealState,
+ action = action,
+ additionalAction = additionalAction,
+ undoAction = undoAction,
+ colors = colors,
+ content = content
+ )
+ }
+
+ @Composable
+ private fun createAction(
+ icon: @Composable () -> Unit = { Icon(SwipeToRevealDefaults.Delete, "Delete") },
+ label: @Composable () -> Unit = { Text("Clear") },
+ modifier: Modifier = Modifier,
+ onClick: () -> Unit = {},
+ ): SwipeToRevealAction = SwipeToRevealDefaults.action(
+ icon = icon,
+ label = label,
+ modifier = modifier.testTag(ACTION_TAG),
+ onClick = onClick
+ )
+
+ @Composable
+ private fun createAdditionalAction(
+ icon: @Composable () -> Unit = { Icon(SwipeToRevealDefaults.MoreOptions, "More Options") },
+ modifier: Modifier = Modifier,
+ onClick: () -> Unit = {},
+ ): SwipeToRevealAction = SwipeToRevealDefaults.additionalAction(
+ icon = icon,
+ modifier = modifier.testTag(ADDITIONAL_ACTION_TAG),
+ onClick = onClick
+ )
+
+ @Composable
+ private fun createUndoAction(
+ label: @Composable () -> Unit = { Text("Undo") },
+ modifier: Modifier = Modifier
+ ) = SwipeToRevealDefaults.undoAction(
+ label = label,
+ modifier = modifier.testTag(UNDO_ACTION_TAG)
+ )
+
+ @Composable
+ private fun createContent(
+ modifier: Modifier = Modifier
+ ) = Box(modifier = modifier
+ .fillMaxWidth()
+ .height(50.dp)
+ .testTag(CONTENT_TAG))
+
+ private val CONTENT_TAG = "Content"
+ private val ACTION_TAG = "Action"
+ private val ADDITIONAL_ACTION_TAG = "AdditionalAction"
+ private val UNDO_ACTION_TAG = "UndoAction"
+}
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt
index 314e312..2f6e8b5 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ContentAlpha.kt
@@ -15,6 +15,7 @@
*/
package androidx.wear.compose.material
+import androidx.annotation.FloatRange
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf
@@ -69,9 +70,9 @@
*/
@Composable
private fun contentAlpha(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
highContrastAlpha: Float,
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
lowContrastAlpha: Float
): Float {
val contentColor = LocalContentColor.current
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt
index 2aaa04b..6587a21 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Picker.kt
@@ -15,6 +15,7 @@
*/
package androidx.wear.compose.material
+import androidx.annotation.FloatRange
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.DecayAnimationSpec
import androidx.compose.animation.core.Easing
@@ -59,11 +60,11 @@
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
-import androidx.wear.compose.foundation.lazy.AutoCenteringParams as AutoCenteringParams
-import androidx.wear.compose.foundation.lazy.ScalingLazyColumn as ScalingLazyColumn
-import androidx.wear.compose.foundation.lazy.ScalingLazyColumnDefaults as ScalingLazyColumnDefaults
-import androidx.wear.compose.foundation.lazy.ScalingLazyListState as ScalingLazyListState
-import androidx.wear.compose.foundation.lazy.ScalingParams as ScalingParams
+import androidx.wear.compose.foundation.lazy.AutoCenteringParams
+import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
+import androidx.wear.compose.foundation.lazy.ScalingLazyColumnDefaults
+import androidx.wear.compose.foundation.lazy.ScalingLazyListState
+import androidx.wear.compose.foundation.lazy.ScalingParams
import kotlinx.coroutines.launch
/**
@@ -120,7 +121,7 @@
onSelected: () -> Unit = {},
scalingParams: ScalingParams = PickerDefaults.defaultScalingParams(),
separation: Dp = 0.dp,
- /* @FloatRange(from = 0.0, to = 0.5) */
+ @FloatRange(from = 0.0, to = 0.5)
gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
gradientColor: Color = MaterialTheme.colors.background,
flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
@@ -245,7 +246,7 @@
onSelected: () -> Unit = {},
scalingParams: androidx.wear.compose.material.ScalingParams = PickerDefaults.scalingParams(),
separation: Dp = 0.dp,
- /* @FloatRange(from = 0.0, to = 0.5) */
+ @FloatRange(from = 0.0, to = 0.5)
gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
gradientColor: Color = MaterialTheme.colors.background,
flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
@@ -322,7 +323,7 @@
onSelected: () -> Unit = {},
scalingParams: androidx.wear.compose.material.ScalingParams = PickerDefaults.scalingParams(),
separation: Dp = 0.dp,
- /* @FloatRange(from = 0.0, to = 0.5) */
+ @FloatRange(from = 0.0, to = 0.5)
gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
gradientColor: Color = MaterialTheme.colors.background,
flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
@@ -389,7 +390,7 @@
readOnlyLabel: @Composable (BoxScope.() -> Unit)? = null,
scalingParams: androidx.wear.compose.material.ScalingParams = PickerDefaults.scalingParams(),
separation: Dp = 0.dp,
- /* @FloatRange(from = 0.0, to = 0.5) */
+ @FloatRange(from = 0.0, to = 0.5)
gradientRatio: Float = PickerDefaults.DefaultGradientRatio,
gradientColor: Color = MaterialTheme.colors.background,
flingBehavior: FlingBehavior = PickerDefaults.flingBehavior(state),
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Placeholder.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Placeholder.kt
index 883e8d4..4cb7df0 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Placeholder.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Placeholder.kt
@@ -211,6 +211,36 @@
}
/**
+ * The current value of the placeholder visual effect gradient progression alpha/opacity during
+ * the fade-in part of reset placeholder animation. This allows the effect to be faded in
+ * during the [PLACEHOLDER_RESET_ANIMATION_DURATION].
+ */
+ internal val resetPlaceholderFadeInAlpha: Float by derivedStateOf {
+ val absoluteProgression =
+ (frameMillis.longValue - startOfResetAnimation - RAPID).coerceAtMost(QUICK.toLong())
+ .toFloat() / QUICK.toFloat()
+ if (absoluteProgression < 0f) {
+ 0f
+ } else {
+ val alpha = lerp(0.1f, 1f, absoluteProgression)
+ resetFadeInInterpolator.transform(alpha)
+ }
+ }
+
+ /**
+ * The current value of the placeholder visual effect gradient progression alpha/opacity during
+ * the fade-out part of reset placeholder animation. This allows the effect to be faded out
+ * during the [PLACEHOLDER_RESET_ANIMATION_DURATION].
+ */
+ internal val resetPlaceholderFadeOutAlpha: Float by derivedStateOf {
+ val absoluteProgression =
+ (frameMillis.longValue - startOfResetAnimation).coerceAtMost(RAPID.toLong())
+ .toFloat() / RAPID.toFloat()
+ val alpha = lerp(1f, 0f, absoluteProgression)
+ resetFadeOutInterpolator.transform(alpha)
+ }
+
+ /**
* Returns true if the placeholder content should be shown with no placeholders effects and
* false if either the placeholder or the wipe-off effect are being shown.
*/
@@ -238,12 +268,13 @@
internal var placeholderStage: PlaceholderStage =
if (isContentReady.value.invoke()) PlaceholderStage.ShowContent
else PlaceholderStage.ShowPlaceholder
- get() {
- if (field != PlaceholderStage.ShowContent) {
+ get() = derivedStateOf {
+ if (field == PlaceholderStage.WipeOff || field == PlaceholderStage.ShowPlaceholder) {
// WipeOff
if (startOfWipeOffAnimation != 0L) {
if ((frameMillis.longValue - startOfWipeOffAnimation) >=
- PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS) {
+ PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS
+ ) {
field = PlaceholderStage.ShowContent
}
// Placeholder
@@ -255,9 +286,29 @@
field = PlaceholderStage.WipeOff
}
}
+ } else {
+ if (!isContentReady.value()) {
+ // Reset
+ if (startOfResetAnimation != 0L) {
+ if (frameMillis.longValue - startOfResetAnimation >=
+ PLACEHOLDER_RESET_ANIMATION_DURATION) {
+ startOfResetAnimation = 0L
+ field = PlaceholderStage.ShowPlaceholder
+ }
+ } else {
+ // ShowContent
+ startOfWipeOffAnimation = 0L
+ if (isReduceMotionEnabled) {
+ field = PlaceholderStage.ShowPlaceholder
+ } else {
+ startOfResetAnimation = frameMillis.longValue
+ field = PlaceholderStage.ResetContent
+ }
+ }
+ }
}
- return field
- }
+ field
+ }.value
/**
* The frame time in milliseconds in the calling context of frame dispatch. Used to coordinate
@@ -265,10 +316,13 @@
*/
internal val frameMillis = mutableLongStateOf(0L)
+ private var startOfResetAnimation = 0L
private var startOfWipeOffAnimation = 0L
private val progressionInterpolator: Easing = CubicBezierEasing(0.3f, 0f, 0.7f, 1f)
private val wipeOffInterpolator: Easing = CubicBezierEasing(0f, 0.2f, 1f, 0.6f)
+ private val resetFadeInInterpolator: Easing = CubicBezierEasing(0.2f, 0f, 0f, 1f)
+ private val resetFadeOutInterpolator: Easing = CubicBezierEasing(0.3f, 0f, 1f, 1f)
}
/**
@@ -596,12 +650,19 @@
* [WipeOff] in the loop after the wire-off animation.
*/
val ShowContent = PlaceholderStage(2)
+
+ /**
+ * Resets the component to remove the content and reinstate the placeholders so that new
+ * content can be loaded. Enter this stage from [ShowContent] and exit to [ShowPlaceholder].
+ */
+ val ResetContent = PlaceholderStage(3)
}
override fun toString(): String {
return when (this) {
ShowPlaceholder -> "PlaceholderStage.ShowPlaceholder"
WipeOff -> "PlaceholderStage.WipeOff"
+ ResetContent -> "PlaceholderStage.ResetContent"
else -> "PlaceholderStage.ShowContent"
}
}
@@ -653,7 +714,8 @@
placeholderState
) to null
}
- PlaceholderStage.ShowPlaceholder -> {
+
+ PlaceholderStage.ShowPlaceholder, PlaceholderStage.ResetContent -> {
if (painter == null) {
SolidColor(color) to null
} else {
@@ -666,6 +728,12 @@
}
}
+ alpha = if (placeholderState.placeholderStage == PlaceholderStage.ResetContent) {
+ 1f - placeholderState.resetPlaceholderFadeOutAlpha
+ } else {
+ 1f
+ }
+
val size = this.size
if (painter != null) {
with(painter) { draw(size = size, alpha = alpha, colorFilter = colorFilter) }
@@ -772,15 +840,20 @@
val shape: Shape
) : AbstractPlaceholderModifier(alpha, shape) {
override fun generateBrush(offset: Offset): Brush? {
- return when (placeholderState.placeholderStage) {
- PlaceholderStage.ShowPlaceholder -> {
- SolidColor(color)
- }
- PlaceholderStage.WipeOff -> {
- wipeOffBrush(color, offset, placeholderState)
- }
- else -> {
- null
+ return when (placeholderState.placeholderStage) {
+ PlaceholderStage.ShowPlaceholder, PlaceholderStage.ResetContent -> {
+ SolidColor(color.copy(
+ alpha =
+ if (placeholderState.placeholderStage == PlaceholderStage.ResetContent) {
+ placeholderState.resetPlaceholderFadeInAlpha * color.alpha
+ } else color.alpha
+ ))
+ }
+ PlaceholderStage.WipeOff -> {
+ wipeOffBrush(color, offset, placeholderState)
+ }
+ else -> {
+ null
}
}
}
@@ -865,3 +938,4 @@
internal const val PLACEHOLDER_WIPE_OFF_PROGRESSION_DURATION_MS = 300L
internal const val PLACEHOLDER_SHIMMER_GAP_BETWEEN_ANIMATION_LOOPS_MS = 2000L
internal const val PLACEHOLDER_WIPE_OFF_PROGRESSION_ALPHA_DURATION_MS = 80L
+internal const val PLACEHOLDER_RESET_ANIMATION_DURATION = 400L
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt
index d5da8bc..77f29fb 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/PositionIndicator.kt
@@ -16,6 +16,7 @@
package androidx.wear.compose.material
+import androidx.annotation.FloatRange
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.AnimationVector
@@ -127,9 +128,7 @@
* Position of the indicator in the range [0f,1f]. 0f means it is at the top|start, 1f means
* it is positioned at the bottom|end.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val positionFraction: Float
/**
@@ -139,10 +138,11 @@
* in pixels depending on orientation of the indicator, (height for vertical, width for
* horizontal)
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
- fun sizeFraction(scrollableContainerSizePx: Float): Float
+ @FloatRange(from = 0.0, to = 1.0)
+ fun sizeFraction(
+ @FloatRange(from = 0.0)
+ scrollableContainerSizePx: Float
+ ): Float
/**
* Should we show the Position Indicator
@@ -151,7 +151,10 @@
* in pixels depending on orientation of the indicator, (height for vertical, width for
* horizontal)
*/
- fun visibility(scrollableContainerSizePx: Float): PositionIndicatorVisibility
+ fun visibility(
+ @FloatRange(from = 0.0)
+ scrollableContainerSizePx: Float
+ ): PositionIndicatorVisibility
}
/**
@@ -223,9 +226,11 @@
* @param reverseDirection Reverses direction of PositionIndicator if true
*/
@Suppress("DEPRECATION")
-@Deprecated("This overload is provided for backwards compatibility with Compose for Wear OS 1.1." +
+@Deprecated(
+ "This overload is provided for backwards compatibility with Compose for Wear OS 1.1." +
"A newer overload is available which uses ScalingLazyListState from " +
- "androidx.wear.compose.foundation.lazy package", level = DeprecationLevel.WARNING)
+ "androidx.wear.compose.foundation.lazy package", level = DeprecationLevel.WARNING
+)
@Composable
public fun PositionIndicator(
scalingLazyListState: androidx.wear.compose.material.ScalingLazyListState,
@@ -782,7 +787,7 @@
if (state.layoutInfo.visibleItemsInfo.isEmpty()) return 0f
val firstItem = state.layoutInfo.visibleItemsInfo.first()
val firstItemStartOffset = firstItem.startOffset(state.layoutInfo.anchorType)
- val viewportStartOffset = - (state.layoutInfo.viewportSize.height / 2f)
+ val viewportStartOffset = -(state.layoutInfo.viewportSize.height / 2f)
// Coerce item size to at least 1 to avoid divide by zero for zero height items
val firstItemInvisibleFraction =
((viewportStartOffset - firstItemStartOffset) /
@@ -866,7 +871,7 @@
if (state.layoutInfo.visibleItemsInfo.isEmpty()) return 0f
val firstItem = state.layoutInfo.visibleItemsInfo.first()
val firstItemStartOffset = firstItem.startOffset(state.anchorType.value!!)
- val viewportStartOffset = - (state.viewportHeightPx.value!! / 2f)
+ val viewportStartOffset = -(state.viewportHeightPx.value!! / 2f)
// Coerce item size to at least 1 to avoid divide by zero for zero height items
val firstItemInvisibleFraction =
((viewportStartOffset - firstItemStartOffset) /
@@ -1122,7 +1127,8 @@
modifier
.transparentSizeModifier(size)
.absoluteOffset { -offset() }, content = content,
- contentAlignment = AbsoluteAlignment.TopLeft)
+ contentAlignment = AbsoluteAlignment.TopLeft
+ )
}
// Sets the size of this element, but lets the child measure using the constraints
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt
index 2b0ebbe..c05d7b5 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ProgressIndicator.kt
@@ -1,5 +1,6 @@
package androidx.wear.compose.material
+import androidx.annotation.FloatRange
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.LinearEasing
@@ -78,7 +79,7 @@
*/
@Composable
public fun CircularProgressIndicator(
- /* @FloatRange(fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0) */
+ @FloatRange(from = 0.0, to = 1.0)
progress: Float,
modifier: Modifier = Modifier,
startAngle: Float = 270f,
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Providers.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Providers.kt
index c9667f9..634663a 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Providers.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Providers.kt
@@ -25,6 +25,19 @@
internal fun <T> provideScopeContent(
contentColor: State<Color>,
+ content: (@Composable T.() -> Unit)
+): (@Composable T.() -> Unit) = {
+ val color = contentColor.value
+ CompositionLocalProvider(
+ LocalContentColor provides color,
+ LocalContentAlpha provides color.alpha,
+ ) {
+ content()
+ }
+}
+
+internal fun <T> provideScopeContent(
+ contentColor: State<Color>,
textStyle: TextStyle,
content: (@Composable T.() -> Unit)
): (@Composable T.() -> Unit) = {
@@ -38,6 +51,18 @@
}
}
+internal fun provideContent(
+ contentColor: State<Color>,
+ content: (@Composable () -> Unit)
+): (@Composable () -> Unit) = {
+ val color = contentColor.value
+ CompositionLocalProvider(
+ LocalContentColor provides color,
+ LocalContentAlpha provides color.alpha,
+ content = content
+ )
+}
+
internal fun provideIcon(
iconColor: State<Color>,
content: (@Composable BoxScope.() -> Unit)
@@ -50,3 +75,35 @@
content()
}
}
+
+internal fun <T> provideNullableScopeContent(
+ contentColor: State<Color>,
+ content: (@Composable T.() -> Unit)?
+): (@Composable T.() -> Unit)? = content?.let {
+ {
+ val color = contentColor.value
+ CompositionLocalProvider(
+ LocalContentColor provides color,
+ LocalContentAlpha provides color.alpha
+ ) {
+ content()
+ }
+ }
+}
+
+internal fun <T> provideNullableScopeContent(
+ contentColor: State<Color>,
+ textStyle: TextStyle,
+ content: (@Composable T.() -> Unit)?
+): (@Composable T.() -> Unit)? = content?.let {
+ {
+ val color = contentColor.value
+ CompositionLocalProvider(
+ LocalContentColor provides color,
+ LocalContentAlpha provides color.alpha,
+ LocalTextStyle provides textStyle
+ ) {
+ content()
+ }
+ }
+}
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
index 382be50..b3abd6e 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyColumnMeasure.kt
@@ -18,6 +18,7 @@
package androidx.wear.compose.material
+import androidx.annotation.FloatRange
import androidx.compose.animation.core.Easing
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.lazy.LazyListItemInfo
@@ -104,9 +105,7 @@
* scaled, e.g. at the edge of the viewport. A value between [0f,1f], so a value of 0.2f
* means to scale an item to 20% of its normal size.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val edgeScale: Float
/**
@@ -114,9 +113,7 @@
* when closest to the edge of the screen. A value between [0f,1f], so a value of
* 0.2f means to set the alpha of an item to 20% of its normal value.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val edgeAlpha: Float
/**
@@ -126,9 +123,7 @@
* will be treated as if [maxElementHeight]. Must be greater than or equal to
* [minElementHeight].
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val minElementHeight: Float
/**
@@ -138,9 +133,7 @@
* will be treated as if [maxElementHeight]. Must be greater than or equal to
* [minElementHeight].
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val maxElementHeight: Float
/**
@@ -157,9 +150,7 @@
* list items exist. Depending on the size of the list item the specific point in the area is
* calculated.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val minTransitionArea: Float
/**
@@ -176,9 +167,7 @@
* list items exist. Depending on the size of the list item the specific point in the area is
* calculated.
*/
-// @FloatRange(
-// fromInclusive = true, from = 0.0, toInclusive = true, to = 1.0
-// )
+ @get:FloatRange(from = 0.0, to = 1.0)
val maxTransitionArea: Float
/**
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt
index d346a0b..2f2c6fad 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ScalingLazyListItemScope.kt
@@ -17,6 +17,7 @@
package androidx.wear.compose.material
+import androidx.annotation.FloatRange
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
@@ -46,7 +47,7 @@
* measured with [Constraints.Infinity] as the constraints for the main axis.
*/
fun Modifier.fillParentMaxSize(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
fraction: Float = 1f
): Modifier
@@ -61,7 +62,7 @@
* items are measured with [Constraints.Infinity] as the constraints for the main axis.
*/
fun Modifier.fillParentMaxWidth(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
fraction: Float = 1f
): Modifier
@@ -76,7 +77,7 @@
* items are measured with [Constraints.Infinity] as the constraints for the main axis.
*/
fun Modifier.fillParentMaxHeight(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
fraction: Float = 1f
): Modifier
}
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToReveal.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToReveal.kt
new file mode 100644
index 0000000..59b4635
--- /dev/null
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/SwipeToReveal.kt
@@ -0,0 +1,537 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.material.icons.outlined.MoreVert
+import androidx.compose.material.ripple.rememberRipple
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
+import androidx.wear.compose.foundation.RevealScope
+import androidx.wear.compose.foundation.RevealState
+import androidx.wear.compose.foundation.RevealValue
+import androidx.wear.compose.foundation.SwipeToReveal
+import kotlin.math.abs
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * [SwipeToReveal] Material composable for Chips. This provides the default style for consistency.
+ *
+ * @see [SwipeToReveal]
+ * @param action An [SwipeToRevealAction] object to describe the primary action when swiping. See
+ * [SwipeToRevealDefaults.action].
+ * @param revealState [RevealState] of the [SwipeToReveal]
+ * @param modifier [Modifier] to be applied on the composable
+ * @param additionalAction An [SwipeToRevealAction] object to describe the contents of addition action.
+ * See [SwipeToRevealDefaults.additionalAction]
+ * @param undoAction An [SwipeToRevealAction] object to describe the contents of undo action. See
+ * [SwipeToRevealDefaults.undoAction].
+ * @param colors An instance of [SwipeToRevealActionColors] to describe the colors of actions. See
+ * [SwipeToRevealDefaults.actionColors].
+ * @param shape The shape of action and additional action composables. Recommended shape for chips
+ * is [Shapes.small].
+ * @param content The initial content shown prior to the swipe-to-reveal gesture.
+ */
+@ExperimentalWearMaterialApi
+@OptIn(ExperimentalWearFoundationApi::class)
+@Composable
+public fun SwipeToRevealChip(
+ action: SwipeToRevealAction,
+ revealState: RevealState,
+ modifier: Modifier = Modifier,
+ additionalAction: SwipeToRevealAction? = null,
+ undoAction: SwipeToRevealAction? = null,
+ colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+ shape: Shape = MaterialTheme.shapes.small,
+ content: @Composable () -> Unit
+) {
+ SwipeToRevealComponent(
+ action = action,
+ revealState = revealState,
+ modifier = modifier,
+ additionalAction = additionalAction,
+ undoAction = undoAction,
+ colors = colors,
+ shape = shape,
+ content = content
+ )
+}
+
+/**
+ * [SwipeToReveal] Material composable for Cards. This provides the default style for consistency.
+ *
+ * @see [SwipeToReveal]
+ * @param action An [SwipeToRevealAction] object to describe the primary action when swiping. See
+ * [SwipeToRevealDefaults.action]
+ * @param revealState [RevealState] of the [SwipeToReveal]
+ * @param modifier [Modifier] to be applied on the composable
+ * @param additionalAction An [SwipeToRevealAction] object to describe the contents of addition action
+ * @param undoAction An [SwipeToRevealAction] object to describe the contents of undo action
+ * @param colors An instance of [SwipeToRevealActionColors] to describe the colors of actions. See
+ * [SwipeToRevealDefaults.actionColors].
+ * @param shape The shape of action and additional action composables. Recommended shape for cards
+ * is [SwipeToRevealDefaults.CardActionShape].
+ * @param content The initial content shown prior to the swipe-to-reveal gesture.
+ */
+@ExperimentalWearMaterialApi
+@OptIn(ExperimentalWearFoundationApi::class)
+@Composable
+public fun SwipeToRevealCard(
+ action: SwipeToRevealAction,
+ revealState: RevealState,
+ modifier: Modifier = Modifier,
+ additionalAction: SwipeToRevealAction? = null,
+ undoAction: SwipeToRevealAction? = null,
+ colors: SwipeToRevealActionColors = SwipeToRevealDefaults.actionColors(),
+ shape: Shape = SwipeToRevealDefaults.CardActionShape,
+ content: @Composable () -> Unit
+) {
+ SwipeToRevealComponent(
+ action = action,
+ revealState = revealState,
+ modifier = modifier,
+ additionalAction = additionalAction,
+ undoAction = undoAction,
+ colors = colors,
+ shape = shape,
+ content = content
+ )
+}
+
+/**
+ * Defaults for Material [SwipeToReveal].
+ */
+@ExperimentalWearMaterialApi
+public object SwipeToRevealDefaults {
+ /**
+ * Recommended shape for [SwipeToReveal] actions when used with [Card].
+ */
+ public val CardActionShape = RoundedCornerShape(40.dp)
+
+ /**
+ * Colors to be used with different actions in [SwipeToReveal].
+ *
+ * @param actionBackgroundColor The background color (color of the shape) of the action
+ * @param actionContentColor The content color (text and icon) of the action
+ * @param additionalActionBackgroundColor The background color (color of the shape) of the
+ * additional action
+ * @param additionalActionContentColor The content color (text and icon) of the additional
+ * action
+ * @param undoActionBackgroundColor The background color (color of the shape) of the undo action
+ * @param undoActionContentColor The content color (text) of the undo action
+ */
+ @Composable
+ public fun actionColors(
+ actionBackgroundColor: Color = MaterialTheme.colors.error,
+ actionContentColor: Color = MaterialTheme.colors.onError,
+ additionalActionBackgroundColor: Color = MaterialTheme.colors.surface,
+ additionalActionContentColor: Color = MaterialTheme.colors.onSurface,
+ undoActionBackgroundColor: Color = MaterialTheme.colors.surface,
+ undoActionContentColor: Color = MaterialTheme.colors.onSurface
+ ): SwipeToRevealActionColors {
+ return SwipeToRevealActionColors(
+ actionBackgroundColor = actionBackgroundColor,
+ actionContentColor = actionContentColor,
+ additionalActionBackgroundColor = additionalActionBackgroundColor,
+ additionalActionContentColor = additionalActionContentColor,
+ undoActionBackgroundColor = undoActionBackgroundColor,
+ undoActionContentColor = undoActionContentColor
+ )
+ }
+
+ /**
+ * Creates a new [SwipeToRevealAction] instance for the primary action parameter of [SwipeToRevealChip] and
+ * [SwipeToRevealCard]. The default behaviour of this action is to animate to
+ * [RevealValue.Revealed] and execute the [onClick] parameter. To override, consider using
+ * [Modifier.clickable].
+ *
+ * @param icon The icon that will be displayed initially on the action
+ * @param label The text that will be displayed on the expanded action
+ * @param modifier [Modifier] to be applied on this action composable
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * interactions with this action.
+ * @param onClick Called when this action is clicked.
+ */
+ @Composable
+ public fun action(
+ icon: @Composable () -> Unit,
+ label: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ onClick: () -> Unit = {}
+ ): SwipeToRevealAction {
+ return SwipeToRevealAction(
+ icon = icon,
+ label = label,
+ modifier = modifier,
+ interactionSource = interactionSource,
+ onClick = onClick
+ )
+ }
+
+ /**
+ * Creates a new [SwipeToRevealAction] instance for the additional action of [SwipeToRevealChip] and
+ * [SwipeToRevealCard]. The default behaviour of this action is to animate to
+ * [RevealValue.Revealed] and execute the [onClick] parameter. To override, consider using
+ * [Modifier.clickable].
+ *
+ * @param icon The icon that will be displayed initially on the screen
+ * @param modifier [Modifier] to be applied on this action composable
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * interactions with this action.
+ * @param onClick Called when this action is clicked.
+ */
+ @Composable
+ public fun additionalAction(
+ icon: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ onClick: () -> Unit = {}
+ ): SwipeToRevealAction {
+ return SwipeToRevealAction(
+ icon = icon,
+ label = null,
+ modifier = modifier,
+ interactionSource = interactionSource,
+ onClick = onClick
+ )
+ }
+
+ /**
+ * Creates a new [SwipeToRevealAction] instance for the undo action of [SwipeToRevealChip] and
+ * [SwipeToRevealCard]. The default behaviour of this action is to snap to
+ * [RevealValue.Covered] and execute the [onClick] parameter. To override, consider using
+ * [Modifier.clickable].
+ *
+ * @param label The text that will be displayed on the undo action composable
+ * @param modifier [Modifier] to be applied on this action composable
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * interactions with this action.
+ * @param onClick Called when this action is clicked.
+ */
+ @Composable
+ public fun undoAction(
+ label: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ onClick: () -> Unit = {}
+ ): SwipeToRevealAction {
+ return SwipeToRevealAction(
+ icon = null,
+ label = label,
+ modifier = modifier,
+ interactionSource = interactionSource,
+ onClick = onClick
+ )
+ }
+
+ /**
+ * [ImageVector] for delete icon, often used for the primary action.
+ */
+ public val Delete = Icons.Outlined.Delete
+
+ /**
+ * [ImageVector] for more options icon, often used for the additional action.
+ */
+ public val MoreOptions = Icons.Outlined.MoreVert
+
+ internal val UndoButtonHorizontalPadding = 14.dp
+ internal val UndoButtonVerticalPadding = 6.dp
+ internal val ActionMaxHeight = 84.dp
+}
+
+/**
+ * A class representing the colors applied in [SwipeToReveal] actions.
+ *
+ * @param actionBackgroundColor Color of the shape (background)
+ * @param actionContentColor Color of icon or text used in the action
+ * @param additionalActionBackgroundColor Color of the additional action shape (background)
+ * @param additionalActionContentColor Color of the icon or text used in the additional action
+ * @param undoActionBackgroundColor Color of the undo action shape (background)
+ * @param undoActionContentColor Color of the icon or text used in the undo action
+ */
+@ExperimentalWearMaterialApi
+public class SwipeToRevealActionColors constructor(
+ val actionBackgroundColor: Color,
+ val actionContentColor: Color,
+ val additionalActionBackgroundColor: Color,
+ val additionalActionContentColor: Color,
+ val undoActionBackgroundColor: Color,
+ val undoActionContentColor: Color
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null) return false
+ if (this::class != other::class) return false
+
+ other as SwipeToRevealActionColors
+
+ if (actionBackgroundColor != other.actionBackgroundColor) return false
+ if (actionContentColor != other.actionContentColor) return false
+ if (additionalActionBackgroundColor != other.additionalActionBackgroundColor) return false
+ if (additionalActionContentColor != other.additionalActionContentColor) return false
+ if (undoActionBackgroundColor != other.undoActionBackgroundColor) return false
+ if (undoActionContentColor != other.undoActionContentColor) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = actionBackgroundColor.hashCode()
+ result = 31 * result + actionContentColor.hashCode()
+ result = 31 * result + additionalActionBackgroundColor.hashCode()
+ result = 31 * result + additionalActionContentColor.hashCode()
+ result = 31 * result + undoActionBackgroundColor.hashCode()
+ result = 31 * result + undoActionContentColor.hashCode()
+ return result
+ }
+}
+
+/**
+ * A class containing the details required for describing the content of an action composable.
+ *
+ * @param icon A slot for providing the icon for this [SwipeToReveal] action
+ * @param label A slot for providing a text label for this [SwipeToRevealAction] action. The
+ * content provided here will be used in different perspective based on the action type
+ * (action, additional action or undo action).
+ * @param modifier The [Modifier] to be applied on the action.
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * interactions with this action.
+ * @param onClick Called when the user clicks the action.
+ */
+@ExperimentalWearMaterialApi
+public class SwipeToRevealAction constructor(
+ val icon: (@Composable () -> Unit)?,
+ val label: (@Composable () -> Unit)?,
+ val modifier: Modifier,
+ val interactionSource: MutableInteractionSource,
+ val onClick: () -> Unit
+) {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null) return false
+ if (this::class != other::class) return false
+
+ other as SwipeToRevealAction
+
+ if (icon != other.icon) return false
+ if (label != other.label) return false
+ if (modifier != other.modifier) return false
+ if (interactionSource != other.interactionSource) return false
+ if (onClick != other.onClick) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = icon.hashCode()
+ result = 31 * result + label.hashCode()
+ result = 31 * result + modifier.hashCode()
+ result = 31 * result + interactionSource.hashCode()
+ result = 31 * result + onClick.hashCode()
+ return result
+ }
+}
+
+@OptIn(ExperimentalWearMaterialApi::class, ExperimentalWearFoundationApi::class)
+@Composable
+private fun SwipeToRevealComponent(
+ action: SwipeToRevealAction,
+ revealState: RevealState,
+ modifier: Modifier,
+ additionalAction: SwipeToRevealAction?,
+ undoAction: SwipeToRevealAction?,
+ colors: SwipeToRevealActionColors,
+ shape: Shape,
+ content: @Composable () -> Unit
+) {
+ val coroutineScope = rememberCoroutineScope()
+ SwipeToReveal(
+ state = revealState,
+ modifier = modifier,
+ onFullSwipe = action.onClick,
+ action = {
+ SwipeToRevealAction(
+ revealState = revealState,
+ coroutineScope = coroutineScope,
+ action = action,
+ backgroundColor = colors.actionBackgroundColor,
+ contentColor = colors.actionContentColor,
+ shape = shape,
+ animateTo = RevealValue.Revealed
+ )
+ },
+ additionalAction =
+ additionalAction?.let {
+ {
+ SwipeToRevealAction(
+ revealState = revealState,
+ coroutineScope = coroutineScope,
+ action = additionalAction,
+ backgroundColor = colors.additionalActionBackgroundColor,
+ contentColor = colors.additionalActionContentColor,
+ shape = shape,
+ animateTo = RevealValue.Revealed
+ )
+ }
+ },
+ undoAction =
+ undoAction?.label?.let {
+ {
+ Box(
+ modifier = undoAction.modifier
+ .clickable(
+ interactionSource = undoAction.interactionSource,
+ indication = rememberRipple(),
+ role = Role.Button,
+ onClick = {
+ coroutineScope.launch { revealState.animateTo(RevealValue.Covered) }
+ undoAction.onClick()
+ }
+ )
+ .clip(CircleShape)
+ .background(color = colors.undoActionBackgroundColor)
+ .padding(
+ horizontal = SwipeToRevealDefaults.UndoButtonHorizontalPadding,
+ vertical = SwipeToRevealDefaults.UndoButtonVerticalPadding
+ ),
+ contentAlignment = Alignment.Center
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides colors.undoActionContentColor
+ ) {
+ undoAction.label.invoke()
+ }
+ }
+ }
+ },
+ content = content
+ )
+}
+
+/**
+ * Action composables for [SwipeToReveal].
+ */
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
+@Composable
+private fun RevealScope.SwipeToRevealAction(
+ revealState: RevealState,
+ coroutineScope: CoroutineScope,
+ action: SwipeToRevealAction,
+ backgroundColor: Color,
+ contentColor: Color,
+ shape: Shape,
+ animateTo: RevealValue
+) {
+ // Change opacity of shape from 0% to 100% between 10% and 20% of the progress
+ val shapeAlpha =
+ if (revealOffset > 0)
+ ((-revealState.offset - revealOffset * 0.1f) / (0.1f * revealOffset))
+ .coerceIn(0.0f, 1.0f)
+ else 1f
+ Row(
+ modifier = action.modifier
+ .graphicsLayer { alpha = shapeAlpha }
+ .background(backgroundColor, shape)
+ // Limit the incoming constraints to max height
+ .heightIn(min = 0.dp, max = SwipeToRevealDefaults.ActionMaxHeight)
+ // Then, fill the max height based on incoming constraints
+ .fillMaxSize()
+ .clickable(
+ interactionSource = action.interactionSource,
+ indication = rememberRipple(),
+ role = Role.Button,
+ onClick = {
+ coroutineScope.launch { revealState.animateTo(animateTo) }
+ action.onClick()
+ }
+ ),
+ horizontalArrangement = Arrangement.Center,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides contentColor
+ ) {
+ if (action.icon != null) {
+ ActionIcon(
+ revealState = revealState,
+ content = action.icon
+ )
+ }
+ if (abs(revealState.offset) > revealOffset && action.label != null) {
+ Spacer(Modifier.size(5.dp))
+ action.label.invoke()
+ }
+ }
+ }
+}
+
+@OptIn(ExperimentalWearFoundationApi::class)
+@Composable
+private fun RevealScope.ActionIcon(
+ revealState: RevealState,
+ content: @Composable () -> Unit
+) {
+ // Change opacity of icons from 0% to 100% between 50% to 75% of the progress
+ val iconAlpha =
+ if (revealOffset > 0)
+ ((-revealState.offset - revealOffset * 0.5f) / (revealOffset * 0.25f))
+ .coerceIn(0.0f, 1.0f)
+ else 1f
+ // Scale icons from 50% to 100% between 50% and 100% of the progress
+ val iconScale =
+ if (revealOffset > 0)
+ ((-revealState.offset - revealOffset * 0.5f) / revealOffset)
+ .coerceIn(0.0f, 0.5f) + 0.5f
+ else 1f
+ Box(
+ modifier = Modifier.graphicsLayer {
+ alpha = iconAlpha
+ scaleX = iconScale
+ scaleY = iconScale
+ }
+ ) {
+ content()
+ }
+}
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt
index 9a6fda0..b605836 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/Swipeable.kt
@@ -16,6 +16,7 @@
package androidx.wear.compose.material
+import androidx.annotation.FloatRange
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.SpringSpec
@@ -442,7 +443,7 @@
class SwipeProgress<T>(
val from: T,
val to: T,
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
val fraction: Float
) {
override fun equals(other: Any?): Boolean {
@@ -660,7 +661,7 @@
@Immutable
@ExperimentalWearMaterialApi
data class FractionalThreshold(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
private val fraction: Float
) : ThresholdConfig {
override fun Density.computeThreshold(fromValue: Float, toValue: Float): Float {
@@ -693,11 +694,11 @@
@Immutable
@ExperimentalWearMaterialApi
class ResistanceConfig(
- /*@FloatRange(from = 0.0, fromInclusive = false)*/
+ @FloatRange(from = 0.0, fromInclusive = false)
val basis: Float,
- /*@FloatRange(from = 0.0)*/
+ @FloatRange(from = 0.0)
val factorAtMin: Float = StandardResistanceFactor,
- /*@FloatRange(from = 0.0)*/
+ @FloatRange(from = 0.0)
val factorAtMax: Float = StandardResistanceFactor
) {
fun computeResistance(overflow: Float): Float {
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleChip.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleChip.kt
index d6b7da3..006e320 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleChip.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleChip.kt
@@ -15,44 +15,23 @@
*/
package androidx.wear.compose.material
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.Interaction
import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.calculateEndPadding
-import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.foundation.layout.defaultMinSize
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.layout.wrapContentHeight
-import androidx.compose.foundation.layout.wrapContentSize
-import androidx.compose.foundation.layout.wrapContentWidth
-import androidx.compose.foundation.selection.toggleable
import androidx.compose.material.icons.materialIcon
import androidx.compose.material.icons.materialPath
-import androidx.compose.material.ripple.rememberRipple
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.draw.paint
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
@@ -64,7 +43,6 @@
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalLayoutDirection
-import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
@@ -141,89 +119,45 @@
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
contentPadding: PaddingValues = ToggleChipDefaults.ContentPadding,
shape: Shape = MaterialTheme.shapes.small,
-) {
- Box(
- modifier = modifier
- .defaultMinSize(minHeight = ToggleChipDefaults.Height)
- .height(IntrinsicSize.Min)
- .clip(shape = shape)
- .width(IntrinsicSize.Max)
- .paint(
- painter = colors.background(enabled = enabled, checked = checked).value,
- contentScale = ContentScale.Crop
- )
- .toggleable(
- enabled = enabled,
- value = checked,
- onValueChange = onCheckedChange,
- role = Role.Checkbox,
- indication = rememberRipple(),
- interactionSource = interactionSource
- )
- ) {
- Row(
- modifier = Modifier
- .fillMaxHeight()
- .padding(contentPadding),
- verticalAlignment = Alignment.CenterVertically
- ) {
- if (appIcon != null) {
- Box(
- modifier = Modifier.wrapContentSize(align = Alignment.Center)
- ) {
- CompositionLocalProvider(
- LocalContentColor provides colors.contentColor(
- enabled = enabled,
- checked = checked
- ).value,
- LocalContentAlpha provides
- colors.contentColor(
- enabled = enabled,
- checked = checked
- ).value.alpha,
- ) {
- appIcon()
- }
- }
- Spacer(modifier = Modifier.size(ToggleChipDefaults.IconSpacing))
- }
- Labels(
- contentColor = colors.contentColor(enabled = enabled, checked = checked).value,
- secondaryContentColor = colors.secondaryContentColor(
- enabled = enabled,
- checked = checked
- ).value,
- label = label,
- secondaryLabel = secondaryLabel,
- )
- Spacer(
- modifier = Modifier.size(
- ToggleChipDefaults.ToggleControlSpacing
- )
- )
- Box(
- modifier = Modifier
- .align(Alignment.CenterVertically)
- .width(24.dp)
- .wrapContentWidth(align = Alignment.End)
- ) {
- CompositionLocalProvider(
- LocalContentColor provides
- colors.toggleControlColor(
- enabled = enabled,
- checked = checked
- ).value,
- LocalContentAlpha provides
- colors.toggleControlColor(
- enabled = enabled,
- checked = checked
- ).value.alpha,
- content = toggleControl
- )
- }
- }
- }
-}
+) = androidx.wear.compose.materialcore.ToggleButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ label = provideScopeContent(
+ contentColor = colors.contentColor(enabled = enabled, checked),
+ textStyle = MaterialTheme.typography.button,
+ content = label
+ ),
+ selectionControl = provideContent(
+ contentColor = colors.toggleControlColor(enabled, checked),
+ content = toggleControl
+ ),
+ modifier = modifier
+ .defaultMinSize(minHeight = ToggleChipDefaults.Height)
+ .height(IntrinsicSize.Min),
+ icon = provideNullableScopeContent(
+ contentColor = colors.contentColor(enabled = enabled, checked = checked),
+ content = appIcon
+ ),
+ secondaryLabel = provideNullableScopeContent(
+ contentColor = colors.secondaryContentColor(enabled = enabled, checked),
+ textStyle = MaterialTheme.typography.caption2,
+ content = secondaryLabel
+ ),
+ background = { isEnabled, isChecked ->
+ val painter = colors.background(
+ enabled = isEnabled,
+ checked = isChecked
+ ).value
+
+ Modifier.paint(painter = painter, contentScale = ContentScale.Crop)
+ },
+ enabled = enabled,
+ interactionSource = interactionSource,
+ contentPadding = contentPadding,
+ shape = shape,
+ selectionControlHeight = TOGGLE_CONTROL_HEIGHT,
+ selectionControlWidth = TOGGLE_CONTROL_WIDTH
+)
/**
* A [SplitToggleChip] is a specialized type of [Chip] that includes a slot for a toggle control,
@@ -309,135 +243,40 @@
clickInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
contentPadding: PaddingValues = ToggleChipDefaults.ContentPadding,
shape: Shape = MaterialTheme.shapes.small,
-) {
- Box(
- modifier = modifier
- .defaultMinSize(minHeight = ToggleChipDefaults.Height)
- .height(IntrinsicSize.Min)
- .width(IntrinsicSize.Max)
- .clip(shape = shape)
- .background(colors.backgroundColor(enabled = enabled).value)
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier.fillMaxHeight()
- ) {
- Row(
- modifier = Modifier
- .clickable(
- enabled = enabled,
- onClick = onClick,
- role = Role.Button,
- indication = rememberRipple(),
- interactionSource = clickInteractionSource,
- )
- .fillMaxHeight()
- .padding(
- start = contentPadding
- .calculateStartPadding(LocalLayoutDirection.current),
- end = 0.dp,
- top = contentPadding.calculateTopPadding(),
- bottom = contentPadding.calculateBottomPadding()
- )
- .weight(1.0f),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Labels(
- contentColor = colors.contentColor(enabled).value,
- secondaryContentColor = colors.secondaryContentColor(enabled = enabled).value,
- label = label,
- secondaryLabel = secondaryLabel,
- )
- Spacer(
- modifier = Modifier
- .size(ToggleChipDefaults.ToggleControlSpacing)
- )
- }
- var splitBoxModifier = Modifier.toggleable(
- enabled = enabled,
- value = checked,
- onValueChange = onCheckedChange,
- role = Role.Checkbox,
- indication = rememberRipple(),
- interactionSource = checkedInteractionSource,
- )
- val splitBackgroundOverlayColor = colors.splitBackgroundOverlay(
- enabled = enabled,
- checked = checked,
- ).value
- splitBoxModifier = splitBoxModifier
- .fillMaxHeight()
- .drawWithContent {
- drawContent()
- drawRect(color = splitBackgroundOverlayColor)
- }
- .align(Alignment.CenterVertically)
- .width(52.dp)
- .wrapContentHeight(align = Alignment.CenterVertically)
- .wrapContentWidth(align = Alignment.End)
- .padding(
- start = 0.dp,
- end = contentPadding
- .calculateEndPadding(
- layoutDirection = LocalLayoutDirection.current
- ),
- top = contentPadding.calculateTopPadding(),
- bottom = contentPadding.calculateBottomPadding()
- )
- Box(
- modifier = splitBoxModifier
- ) {
- CompositionLocalProvider(
- LocalContentColor provides
- colors.toggleControlColor(
- enabled = enabled,
- checked = checked
- ).value,
- LocalContentAlpha provides
- colors.toggleControlColor(
- enabled = enabled,
- checked = checked
- ).value.alpha,
- ) {
- toggleControl()
- }
- }
- }
- }
-}
-
-@Composable
-private fun RowScope.Labels(
- contentColor: Color,
- secondaryContentColor: Color,
- label: @Composable RowScope.() -> Unit,
- secondaryLabel: @Composable (RowScope.() -> Unit)?
-) {
- Column(modifier = Modifier.weight(1.0f)) {
- Row {
- CompositionLocalProvider(
- LocalContentColor provides
- contentColor,
- LocalTextStyle provides MaterialTheme.typography.button,
- LocalContentAlpha provides
- contentColor.alpha,
- ) {
- label()
- }
- }
- if (secondaryLabel != null) {
- Row {
- CompositionLocalProvider(
- LocalContentColor provides secondaryContentColor,
- LocalTextStyle provides MaterialTheme.typography.caption2,
- LocalContentAlpha provides secondaryContentColor.alpha,
- ) {
- secondaryLabel()
- }
- }
- }
- }
-}
+) = androidx.wear.compose.materialcore.SplitToggleButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ label = provideScopeContent(
+ contentColor = colors.contentColor(enabled = enabled),
+ textStyle = MaterialTheme.typography.button,
+ content = label
+ ),
+ onClick = onClick,
+ selectionControl = provideScopeContent(
+ contentColor = colors.toggleControlColor(enabled = enabled, checked = checked),
+ content = toggleControl
+ ),
+ modifier = modifier
+ .defaultMinSize(minHeight = ToggleChipDefaults.Height)
+ .height(IntrinsicSize.Min),
+ secondaryLabel = provideNullableScopeContent(
+ contentColor = colors.secondaryContentColor(enabled = enabled),
+ textStyle = MaterialTheme.typography.caption2,
+ content = secondaryLabel
+ ),
+ backgroundColor = { isEnabled, _ -> colors.backgroundColor(enabled = isEnabled) },
+ splitBackgroundColor = { isEnabled, isChecked ->
+ colors.splitBackgroundOverlay(
+ enabled = isEnabled,
+ checked = isChecked
+ )
+ },
+ enabled = enabled,
+ checkedInteractionSource = checkedInteractionSource,
+ clickInteractionSource = clickInteractionSource,
+ contentPadding = contentPadding,
+ shape = shape
+)
/**
* Represents the background and content colors used in [ToggleChip]s
@@ -1227,3 +1066,6 @@
return result
}
}
+
+private val TOGGLE_CONTROL_HEIGHT = 24.dp
+private val TOGGLE_CONTROL_WIDTH = 24.dp
diff --git a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleControl.kt b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleControl.kt
index db56184..cabf021 100644
--- a/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleControl.kt
+++ b/wear/compose/compose-material/src/main/java/androidx/wear/compose/material/ToggleControl.kt
@@ -84,7 +84,7 @@
enabled = enabled,
onCheckedChange = onCheckedChange,
interactionSource = interactionSource,
- drawBox = { drawScope, color, _ -> drawScope.drawBox(color) },
+ drawBox = { drawScope, color, _, _ -> drawScope.drawBox(color) },
progressAnimationSpec = PROGRESS_ANIMATION_SPEC,
width = WIDTH,
height = HEIGHT
diff --git a/wear/compose/compose-material3/api/current.txt b/wear/compose/compose-material3/api/current.txt
index f06a597c..aab9c95 100644
--- a/wear/compose/compose-material3/api/current.txt
+++ b/wear/compose/compose-material3/api/current.txt
@@ -488,24 +488,64 @@
@androidx.compose.runtime.Immutable public final class ToggleButtonColors {
ctor public ToggleButtonColors(long checkedContainerColor, long checkedContentColor, long uncheckedContainerColor, long uncheckedContentColor, long disabledCheckedContainerColor, long disabledCheckedContentColor, long disabledUncheckedContainerColor, long disabledUncheckedContentColor);
+ ctor public ToggleButtonColors(long checkedContainerColor, long checkedContentColor, long checkedSecondaryContentColor, long checkedIconColor, long checkedSplitContainerColor, long uncheckedContainerColor, long uncheckedContentColor, long uncheckedSecondaryContentColor, long uncheckedIconColor, long uncheckedSplitContainerColor, long disabledCheckedContainerColor, long disabledCheckedContentColor, long disabledCheckedSecondaryContentColor, long disabledCheckedIconColor, long disabledCheckedSplitContainerColor, long disabledUncheckedContainerColor, long disabledUncheckedContentColor, long disabledUncheckedSecondaryContentColor, long disabledUncheckedIconColor, long disabledUncheckedSplitContainerColor);
method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled, boolean checked);
method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
method public long getCheckedContainerColor();
method public long getCheckedContentColor();
+ method public long getCheckedIconColor();
+ method public long getCheckedSecondaryContentColor();
+ method public long getCheckedSplitContainerColor();
method public long getDisabledCheckedContainerColor();
method public long getDisabledCheckedContentColor();
+ method public long getDisabledCheckedIconColor();
+ method public long getDisabledCheckedSecondaryContentColor();
+ method public long getDisabledCheckedSplitContainerColor();
method public long getDisabledUncheckedContainerColor();
method public long getDisabledUncheckedContentColor();
+ method public long getDisabledUncheckedIconColor();
+ method public long getDisabledUncheckedSecondaryContentColor();
+ method public long getDisabledUncheckedSplitContainerColor();
method public long getUncheckedContainerColor();
method public long getUncheckedContentColor();
+ method public long getUncheckedIconColor();
+ method public long getUncheckedSecondaryContentColor();
+ method public long getUncheckedSplitContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean enabled, boolean checked);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled, boolean checked);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> splitContainerColor(boolean enabled, boolean checked);
property public final long checkedContainerColor;
property public final long checkedContentColor;
+ property public final long checkedIconColor;
+ property public final long checkedSecondaryContentColor;
+ property public final long checkedSplitContainerColor;
property public final long disabledCheckedContainerColor;
property public final long disabledCheckedContentColor;
+ property public final long disabledCheckedIconColor;
+ property public final long disabledCheckedSecondaryContentColor;
+ property public final long disabledCheckedSplitContainerColor;
property public final long disabledUncheckedContainerColor;
property public final long disabledUncheckedContentColor;
+ property public final long disabledUncheckedIconColor;
+ property public final long disabledUncheckedSecondaryContentColor;
+ property public final long disabledUncheckedSplitContainerColor;
property public final long uncheckedContainerColor;
property public final long uncheckedContentColor;
+ property public final long uncheckedIconColor;
+ property public final long uncheckedSecondaryContentColor;
+ property public final long uncheckedSplitContainerColor;
+ }
+
+ public final class ToggleButtonDefaults {
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.ToggleButtonColors toggleButtonColors(optional long checkedContainerColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedIconColor, optional long checkedSplitContainerColor, optional long uncheckedContainerColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedIconColor, optional long uncheckedSplitContainerColor);
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ field public static final androidx.wear.compose.material3.ToggleButtonDefaults INSTANCE;
+ }
+
+ public final class ToggleButtonKt {
+ method @androidx.compose.runtime.Composable public static void SplitToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> selectionControl, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.wear.compose.material3.ToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource checkedInteractionSource, optional androidx.compose.foundation.interaction.MutableInteractionSource clickInteractionSource, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? secondaryLabel, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
+ method @androidx.compose.runtime.Composable public static void ToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, kotlin.jvm.functions.Function0<kotlin.Unit> selectionControl, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.wear.compose.material3.ToggleButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? secondaryLabel, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
}
public final class TouchTargetAwareSizeKt {
diff --git a/wear/compose/compose-material3/api/restricted_current.txt b/wear/compose/compose-material3/api/restricted_current.txt
index f06a597c..aab9c95 100644
--- a/wear/compose/compose-material3/api/restricted_current.txt
+++ b/wear/compose/compose-material3/api/restricted_current.txt
@@ -488,24 +488,64 @@
@androidx.compose.runtime.Immutable public final class ToggleButtonColors {
ctor public ToggleButtonColors(long checkedContainerColor, long checkedContentColor, long uncheckedContainerColor, long uncheckedContentColor, long disabledCheckedContainerColor, long disabledCheckedContentColor, long disabledUncheckedContainerColor, long disabledUncheckedContentColor);
+ ctor public ToggleButtonColors(long checkedContainerColor, long checkedContentColor, long checkedSecondaryContentColor, long checkedIconColor, long checkedSplitContainerColor, long uncheckedContainerColor, long uncheckedContentColor, long uncheckedSecondaryContentColor, long uncheckedIconColor, long uncheckedSplitContainerColor, long disabledCheckedContainerColor, long disabledCheckedContentColor, long disabledCheckedSecondaryContentColor, long disabledCheckedIconColor, long disabledCheckedSplitContainerColor, long disabledUncheckedContainerColor, long disabledUncheckedContentColor, long disabledUncheckedSecondaryContentColor, long disabledUncheckedIconColor, long disabledUncheckedSplitContainerColor);
method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> containerColor(boolean enabled, boolean checked);
method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> contentColor(boolean enabled, boolean checked);
method public long getCheckedContainerColor();
method public long getCheckedContentColor();
+ method public long getCheckedIconColor();
+ method public long getCheckedSecondaryContentColor();
+ method public long getCheckedSplitContainerColor();
method public long getDisabledCheckedContainerColor();
method public long getDisabledCheckedContentColor();
+ method public long getDisabledCheckedIconColor();
+ method public long getDisabledCheckedSecondaryContentColor();
+ method public long getDisabledCheckedSplitContainerColor();
method public long getDisabledUncheckedContainerColor();
method public long getDisabledUncheckedContentColor();
+ method public long getDisabledUncheckedIconColor();
+ method public long getDisabledUncheckedSecondaryContentColor();
+ method public long getDisabledUncheckedSplitContainerColor();
method public long getUncheckedContainerColor();
method public long getUncheckedContentColor();
+ method public long getUncheckedIconColor();
+ method public long getUncheckedSecondaryContentColor();
+ method public long getUncheckedSplitContainerColor();
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> iconColor(boolean enabled, boolean checked);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> secondaryContentColor(boolean enabled, boolean checked);
+ method @androidx.compose.runtime.Composable public androidx.compose.runtime.State<androidx.compose.ui.graphics.Color> splitContainerColor(boolean enabled, boolean checked);
property public final long checkedContainerColor;
property public final long checkedContentColor;
+ property public final long checkedIconColor;
+ property public final long checkedSecondaryContentColor;
+ property public final long checkedSplitContainerColor;
property public final long disabledCheckedContainerColor;
property public final long disabledCheckedContentColor;
+ property public final long disabledCheckedIconColor;
+ property public final long disabledCheckedSecondaryContentColor;
+ property public final long disabledCheckedSplitContainerColor;
property public final long disabledUncheckedContainerColor;
property public final long disabledUncheckedContentColor;
+ property public final long disabledUncheckedIconColor;
+ property public final long disabledUncheckedSecondaryContentColor;
+ property public final long disabledUncheckedSplitContainerColor;
property public final long uncheckedContainerColor;
property public final long uncheckedContentColor;
+ property public final long uncheckedIconColor;
+ property public final long uncheckedSecondaryContentColor;
+ property public final long uncheckedSplitContainerColor;
+ }
+
+ public final class ToggleButtonDefaults {
+ method public androidx.compose.foundation.layout.PaddingValues getContentPadding();
+ method @androidx.compose.runtime.Composable public androidx.wear.compose.material3.ToggleButtonColors toggleButtonColors(optional long checkedContainerColor, optional long checkedContentColor, optional long checkedSecondaryContentColor, optional long checkedIconColor, optional long checkedSplitContainerColor, optional long uncheckedContainerColor, optional long uncheckedContentColor, optional long uncheckedSecondaryContentColor, optional long uncheckedIconColor, optional long uncheckedSplitContainerColor);
+ property public final androidx.compose.foundation.layout.PaddingValues ContentPadding;
+ field public static final androidx.wear.compose.material3.ToggleButtonDefaults INSTANCE;
+ }
+
+ public final class ToggleButtonKt {
+ method @androidx.compose.runtime.Composable public static void SplitToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit> selectionControl, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.wear.compose.material3.ToggleButtonColors colors, optional androidx.compose.foundation.interaction.MutableInteractionSource checkedInteractionSource, optional androidx.compose.foundation.interaction.MutableInteractionSource clickInteractionSource, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? secondaryLabel, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
+ method @androidx.compose.runtime.Composable public static void ToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, kotlin.jvm.functions.Function0<kotlin.Unit> selectionControl, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional androidx.compose.ui.graphics.Shape shape, optional androidx.wear.compose.material3.ToggleButtonColors colors, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? icon, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit>? secondaryLabel, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.RowScope,kotlin.Unit> label);
}
public final class TouchTargetAwareSizeKt {
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ToggleButtonDemo.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ToggleButtonDemo.kt
new file mode 100644
index 0000000..d758105
--- /dev/null
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/ToggleButtonDemo.kt
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3.demos
+
+import android.content.Context
+import android.widget.Toast
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
+import androidx.wear.compose.foundation.lazy.ScalingLazyListScope
+import androidx.wear.compose.integration.demos.common.Centralize
+import androidx.wear.compose.integration.demos.common.ComposableDemo
+import androidx.wear.compose.integration.demos.common.DemoCategory
+import androidx.wear.compose.material3.Checkbox
+import androidx.wear.compose.material3.Icon
+import androidx.wear.compose.material3.ListHeader
+import androidx.wear.compose.material3.RadioButton
+import androidx.wear.compose.material3.SplitToggleButton
+import androidx.wear.compose.material3.Switch
+import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.ToggleButton
+import androidx.wear.compose.material3.samples.SplitToggleButtonWithCheckbox
+import androidx.wear.compose.material3.samples.SplitToggleButtonWithRadioButton
+import androidx.wear.compose.material3.samples.SplitToggleButtonWithSwitch
+import androidx.wear.compose.material3.samples.ToggleButtonWithCheckbox
+import androidx.wear.compose.material3.samples.ToggleButtonWithRadioButton
+import androidx.wear.compose.material3.samples.ToggleButtonWithSwitch
+
+val toggleButtonDemos = listOf(
+ DemoCategory(
+ "Samples",
+ listOf(
+ ComposableDemo("ToggleButtonWithCheckbox sample") {
+ Centralize(Modifier.padding(horizontal = 10.dp)) {
+ ToggleButtonWithCheckbox()
+ }
+ },
+ ComposableDemo("ToggleButtonWithSwitch sample") {
+ Centralize(Modifier.padding(horizontal = 10.dp)) {
+ ToggleButtonWithSwitch()
+ }
+ },
+ ComposableDemo("ToggleButtonWithRadioButton sample") {
+ Centralize(Modifier.padding(horizontal = 10.dp)) {
+ ToggleButtonWithRadioButton()
+ }
+ },
+ ComposableDemo("SplitToggleButtonWithCheckbox sample") {
+ Centralize(Modifier.padding(horizontal = 10.dp)) {
+ SplitToggleButtonWithCheckbox()
+ }
+ },
+ ComposableDemo("SplitToggleButtonWithSwitch sample") {
+ Centralize(Modifier.padding(horizontal = 10.dp)) {
+ SplitToggleButtonWithSwitch()
+ }
+ },
+ ComposableDemo("SplitToggleButtonWithRadioButton sample") {
+ Centralize(Modifier.padding(horizontal = 10.dp)) {
+ SplitToggleButtonWithRadioButton()
+ }
+ },
+ )
+ ),
+ DemoCategory("Demos", listOf(
+ ComposableDemo("ToggleButton demos") {
+ ToggleButtonDemos()
+ },
+ ComposableDemo("SplitToggleButton demos") {
+ SplitToggleButtonDemos()
+ }
+ ))
+)
+
+@Composable
+private fun ToggleButtonDemos() {
+ var enabledState by remember { mutableStateOf(true) }
+
+ ScalingLazyColumn(
+ modifier = Modifier
+ .fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ item {
+ val buttonState = if (enabledState) "Enabled" else "Disabled"
+ ListHeader { Text(text = "State: $buttonState") }
+ }
+ item {
+ Switch(checked = enabledState, onCheckedChange = { enabledState = it })
+ }
+ item {
+ ListHeader { Text(text = "State:") }
+ }
+ addToggleButtonVariations(enabled = enabledState, primaryLabel = "Primary Label")
+
+ addToggleButtonVariations(enabled = enabledState, icon = {
+ Icon(imageVector = Icons.Filled.Add, contentDescription = "icon")
+ }, primaryLabel = "Primary Label")
+
+ addToggleButtonVariations(enabled = enabledState, icon = {
+ Icon(imageVector = Icons.Filled.Add, contentDescription = "icon")
+ }, primaryLabel = "Primary", secondaryLabel = "Secondary")
+
+ addToggleButtonVariations(
+ enabled = enabledState,
+ primaryLabel = "Primary Label",
+ secondaryLabel = "Secondary"
+ )
+ addToggleButtonVariations(
+ enabled = enabledState,
+ primaryLabel = "Primary Label with 3 lines of content max"
+ )
+ addToggleButtonVariations(
+ enabled = enabledState,
+ primaryLabel = "Primary Label with 3 lines of content max",
+ secondaryLabel = "Secondary label with 2 lines"
+ )
+ }
+}
+
+@Composable
+private fun SplitToggleButtonDemos() {
+ val context = LocalContext.current
+ var enabledState by remember { mutableStateOf(true) }
+
+ ScalingLazyColumn(
+ modifier = Modifier
+ .fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ item {
+ val buttonState = if (enabledState) "Enabled" else "Disabled"
+ ListHeader { Text(text = "State: $buttonState") }
+ }
+ item {
+ Switch(checked = enabledState, onCheckedChange = { enabledState = it })
+ }
+ item {
+ ListHeader { Text(text = "State:") }
+ }
+ addSplitToggleButtonVariations(
+ enabled = enabledState,
+ primaryLabel = "8:15AM",
+ secondaryLabel = "Mon, Tue, Wed",
+ context = context
+ )
+
+ addSplitToggleButtonVariations(
+ enabled = enabledState,
+ primaryLabel = "Primary Label with 3 lines of content max",
+ secondaryLabel = "Secondary label 2 lines",
+ context = context
+ )
+ }
+}
+
+private fun ScalingLazyListScope.addToggleButtonVariations(
+ enabled: Boolean,
+ icon: @Composable (BoxScope.() -> Unit)? = null,
+ primaryLabel: String,
+ secondaryLabel: String? = null
+) {
+ val selectionControls =
+ listOf(ToggleControl.CHECKBOX, ToggleControl.SWITCH, ToggleControl.RADIO)
+ for (selectionControl in selectionControls) {
+ item {
+ var checked by remember {
+ mutableStateOf(true)
+ }
+
+ ToggleButton(checked = checked,
+ enabled = enabled,
+ onCheckedChange = {
+ checked = it
+ },
+ icon = icon,
+ label = {
+ Text(primaryLabel)
+ }, selectionControl = {
+
+ when (selectionControl) {
+ ToggleControl.CHECKBOX -> Checkbox(checked = checked, enabled = enabled)
+ ToggleControl.SWITCH -> Switch(checked = checked, enabled = enabled)
+ ToggleControl.RADIO -> RadioButton(selected = checked, enabled = enabled)
+ }
+ },
+ secondaryLabel = {
+ secondaryLabel?.let {
+ Text(secondaryLabel)
+ }
+ }
+ )
+ }
+ }
+}
+
+private fun ScalingLazyListScope.addSplitToggleButtonVariations(
+ enabled: Boolean,
+ primaryLabel: String,
+ secondaryLabel: String? = null,
+ context: Context
+) {
+ val selectionControls =
+ listOf(ToggleControl.CHECKBOX, ToggleControl.SWITCH, ToggleControl.RADIO)
+ for (selectionControl in selectionControls) {
+ item {
+ var checked by remember {
+ mutableStateOf(true)
+ }
+
+ SplitToggleButton(checked = checked,
+ enabled = enabled,
+ onCheckedChange = {
+ checked = it
+ },
+ onClick = {
+ Toast.makeText(
+ context, "Text was clicked",
+ Toast.LENGTH_SHORT
+ ).show()
+ },
+ label = {
+ Text(primaryLabel)
+ }, selectionControl = {
+
+ when (selectionControl) {
+ ToggleControl.CHECKBOX -> Checkbox(checked = checked, enabled = enabled)
+ ToggleControl.SWITCH -> Switch(checked = checked, enabled = enabled)
+ ToggleControl.RADIO -> RadioButton(selected = checked, enabled = enabled)
+ }
+ },
+ secondaryLabel = {
+ secondaryLabel?.let {
+ Text(secondaryLabel)
+ }
+ }
+ )
+ }
+ }
+}
+
+private enum class ToggleControl {
+ CHECKBOX, RADIO, SWITCH
+}
diff --git a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
index c239cfe..432f227 100644
--- a/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
+++ b/wear/compose/compose-material3/integration-tests/src/main/java/androidx/wear/compose/material3/demos/WearMaterial3Demos.kt
@@ -106,6 +106,10 @@
selectionControlsDemos
),
DemoCategory(
+ title = "Toggle Button",
+ toggleButtonDemos
+ ),
+ DemoCategory(
title = "Swipe To Dismiss",
listOf(
ComposableDemo("Simple") { SimpleSwipeToDismissBox(it.navigateBack) },
diff --git a/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ToggleButtonSample.kt b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ToggleButtonSample.kt
new file mode 100644
index 0000000..af19d95
--- /dev/null
+++ b/wear/compose/compose-material3/samples/src/main/java/androidx/wear/compose/material3/samples/ToggleButtonSample.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.contentDescription
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.wear.compose.material3.Checkbox
+import androidx.wear.compose.material3.Icon
+import androidx.wear.compose.material3.RadioButton
+import androidx.wear.compose.material3.SplitToggleButton
+import androidx.wear.compose.material3.Switch
+import androidx.wear.compose.material3.Text
+import androidx.wear.compose.material3.ToggleButton
+
+@Sampled
+@Composable
+fun ToggleButtonWithCheckbox() {
+ var checked by remember { mutableStateOf(true) }
+ ToggleButton(
+ label = {
+ Text("SwitchIcon", maxLines = 1, overflow = TextOverflow.Ellipsis)
+ },
+ secondaryLabel = {
+ Text("With secondary label", maxLines = 1, overflow = TextOverflow.Ellipsis)
+ },
+ checked = checked,
+ selectionControl = {
+ Checkbox(
+ checked = checked,
+ enabled = true,
+ modifier = Modifier.semantics {
+ this.contentDescription =
+ if (checked) "On" else "Off"
+ }
+ )
+ },
+ onCheckedChange = { checked = it },
+ icon = {
+ Icon(
+ Icons.Filled.Favorite,
+ contentDescription = "Favorite icon"
+ )
+ },
+ enabled = true,
+ )
+}
+
+@Sampled
+@Composable
+fun ToggleButtonWithSwitch() {
+ var checked by remember { mutableStateOf(true) }
+ ToggleButton(
+ label = {
+ Text("SwitchIcon", maxLines = 1, overflow = TextOverflow.Ellipsis)
+ },
+ secondaryLabel = {
+ Text("With secondary label", maxLines = 1, overflow = TextOverflow.Ellipsis)
+ },
+ checked = checked,
+ selectionControl = {
+ Switch(
+ checked = checked,
+ enabled = true,
+ modifier = Modifier.semantics {
+ this.contentDescription =
+ if (checked) "On" else "Off"
+ }
+ )
+ },
+ onCheckedChange = { checked = it },
+ icon = {
+ Icon(
+ Icons.Filled.Favorite,
+ contentDescription = "Favorite icon"
+ )
+ },
+ enabled = true,
+ )
+}
+
+@Sampled
+@Composable
+fun ToggleButtonWithRadioButton() {
+ var selected by remember { mutableStateOf(true) }
+ ToggleButton(
+ label = {
+ Text("RadioIcon", maxLines = 1, overflow = TextOverflow.Ellipsis)
+ },
+ secondaryLabel = {
+ Text("With secondary label", maxLines = 1, overflow = TextOverflow.Ellipsis)
+ },
+ checked = selected,
+ selectionControl = {
+ RadioButton(
+ selected = selected,
+ enabled = true,
+ modifier = Modifier.semantics {
+ this.contentDescription =
+ if (selected) "On" else "Off"
+ }
+ )
+ },
+ onCheckedChange = { selected = it },
+ icon = {
+ Icon(
+ Icons.Filled.Favorite,
+ contentDescription = "Favorite icon"
+ )
+ },
+ enabled = true,
+ )
+}
+
+@Sampled
+@Composable
+fun SplitToggleButtonWithCheckbox() {
+ var checked by remember { mutableStateOf(true) }
+ SplitToggleButton(
+ label = {
+ Text("Split with CheckboxIcon", maxLines = 2, overflow = TextOverflow.Ellipsis)
+ },
+ checked = checked,
+ selectionControl = {
+ Checkbox(
+ checked = checked,
+ enabled = true,
+ modifier = Modifier.semantics {
+ this.contentDescription =
+ if (checked) "Checked" else "Unchecked"
+ }
+ )
+ },
+ onCheckedChange = { checked = it },
+ onClick = {
+ /* Do something */
+ },
+ enabled = true,
+ )
+}
+
+@Sampled
+@Composable
+fun SplitToggleButtonWithSwitch() {
+ var checked by remember { mutableStateOf(true) }
+ SplitToggleButton(
+ label = {
+ Text("Split with CheckboxIcon", maxLines = 2, overflow = TextOverflow.Ellipsis)
+ },
+ checked = checked,
+ selectionControl = {
+ Switch(
+ checked = checked,
+ enabled = true,
+ modifier = Modifier.semantics {
+ this.contentDescription =
+ if (checked) "Checked" else "Unchecked"
+ }
+ )
+ },
+ onCheckedChange = { checked = it },
+ onClick = {
+ /* Do something */
+ },
+ enabled = true,
+ )
+}
+
+@Sampled
+@Composable
+fun SplitToggleButtonWithRadioButton() {
+ var selected by remember { mutableStateOf(true) }
+ SplitToggleButton(
+ label = {
+ Text("Split with CheckboxIcon", maxLines = 2, overflow = TextOverflow.Ellipsis)
+ },
+ checked = selected,
+ selectionControl = {
+ Checkbox(
+ checked = selected,
+ enabled = true,
+ modifier = Modifier.semantics {
+ this.contentDescription =
+ if (selected) "On" else "Off"
+ }
+ )
+ },
+ onCheckedChange = { selected = it },
+ onClick = {
+ /* Do something */
+ },
+ enabled = true,
+ )
+}
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonScreenshotTest.kt
new file mode 100644
index 0000000..3903cba
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/IconToggleButtonScreenshotTest.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3
+
+import android.os.Build
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Star
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class IconToggleButtonScreenshotTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @get:Rule
+ val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+ @get:Rule
+ val testName = TestName()
+
+ @Test
+ fun iconToggleButtonEnabledAndChecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleIconToggleButton() }
+ )
+
+ @Test
+ fun iconToggleButtonEnabledAndUnchecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleIconToggleButton(checked = false) }
+ )
+
+ @Test
+ fun iconToggleButtonDisabledAndChecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleIconToggleButton(enabled = false) }
+ )
+
+ @Test
+ fun iconToggleButtonDisabledAndUnchecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleIconToggleButton(enabled = false, checked = false) }
+ )
+
+ @Composable
+ private fun sampleIconToggleButton(
+ enabled: Boolean = true,
+ checked: Boolean = true
+ ) {
+ IconToggleButton(
+ checked = checked,
+ onCheckedChange = {},
+ enabled = enabled,
+ modifier = Modifier.testTag(TEST_TAG)
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Star,
+ contentDescription = "Favourite"
+ )
+ }
+ }
+}
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
index afa5a80..093455c 100644
--- a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/Material3Test.kt
@@ -30,6 +30,7 @@
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
import androidx.compose.runtime.Composable
+import androidx.compose.testutils.assertAgainstGolden
import androidx.compose.testutils.assertContainsColor
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -53,6 +54,7 @@
import androidx.compose.ui.unit.height
import androidx.compose.ui.unit.isUnspecified
import androidx.compose.ui.unit.toSize
+import androidx.test.screenshot.AndroidXScreenshotTestRule
import kotlin.math.abs
import org.junit.Assert
@@ -279,6 +281,27 @@
}
}
+@RequiresApi(Build.VERSION_CODES.O)
+internal fun ComposeContentTestRule.verifyScreenshot(
+ methodName: String,
+ screenshotRule: AndroidXScreenshotTestRule,
+ testTag: String = TEST_TAG,
+ content: @Composable () -> Unit
+) {
+ setContentWithTheme {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.background)
+ ) {
+ content()
+ }
+ }
+
+ onNodeWithTag(testTag).captureToImage()
+ .assertAgainstGolden(screenshotRule, methodName)
+}
+
private fun ImageBitmap.histogram(): MutableMap<Color, Long> {
val pixels = this.toPixelMap()
val histogram = mutableMapOf<Color, Long>()
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonScreenshotTest.kt
new file mode 100644
index 0000000..71a30a6
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/TextToggleButtonScreenshotTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3
+
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class TextToggleButtonScreenshotTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @get:Rule
+ val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+ @get:Rule
+ val testName = TestName()
+
+ @Test
+ fun textToggleButtonEnabledAndChecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleTextToggleButton() }
+ )
+
+ @Test
+ fun textToggleButtonEnabledAndUnchecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleTextToggleButton(checked = false) }
+ )
+
+ @Test
+ fun textToggleButtonDisabledAndChecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleTextToggleButton(enabled = false) }
+ )
+
+ @Test
+ fun textToggleButtonDisabledAndUnchecked() = rule.verifyScreenshot(
+ methodName = testName.methodName,
+ screenshotRule = screenshotRule,
+ content = { sampleTextToggleButton(enabled = false, checked = false) }
+ )
+
+ @Composable
+ private fun sampleTextToggleButton(
+ enabled: Boolean = true,
+ checked: Boolean = true
+ ) {
+ TextToggleButton(
+ checked = checked,
+ onCheckedChange = {},
+ enabled = enabled,
+ modifier = Modifier.testTag(TEST_TAG)) {
+ Text(text = if (checked) "ON" else "OFF")
+ }
+ }
+}
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ToggleButtonScreenshotTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ToggleButtonScreenshotTest.kt
new file mode 100644
index 0000000..41b89f4
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ToggleButtonScreenshotTest.kt
@@ -0,0 +1,643 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3
+
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.testutils.assertAgainstGolden
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalLayoutDirection
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.test.screenshot.AndroidXScreenshotTestRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestName
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+class ToggleButtonScreenshotTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @get:Rule
+ val screenshotRule = AndroidXScreenshotTestRule(SCREENSHOT_GOLDEN_PATH)
+
+ @get:Rule
+ val testName = TestName()
+
+ @Test
+ fun toggle_button_checked_checkbox() = verifyScreenshot {
+ sampleToggleButton(
+ checked = true,
+ selectionControl = {
+ Checkbox(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_unchecked_checkbox() = verifyScreenshot {
+ sampleToggleButton(
+ checked = false,
+ selectionControl = {
+ Checkbox(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_checked_switch() = verifyScreenshot {
+ sampleToggleButton(
+ checked = true,
+ selectionControl = {
+ Switch(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_unchecked_switch() = verifyScreenshot {
+ sampleToggleButton(
+ checked = false,
+ selectionControl = {
+ Switch(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_selected_radio() = verifyScreenshot {
+ sampleToggleButton(
+ checked = true,
+ selectionControl = {
+ RadioButton(selected = true)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_unselected_radio() = verifyScreenshot {
+ sampleToggleButton(
+ checked = false,
+ selectionControl = {
+ RadioButton(selected = false)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_checked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = true,
+ selectionControl = {
+ Checkbox(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_unchecked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = false,
+ selectionControl = {
+ Checkbox(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_checked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = true,
+ selectionControl = {
+ Switch(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_unchecked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = false,
+ selectionControl = {
+ Switch(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_selected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = true,
+ selectionControl = {
+ RadioButton(selected = true)
+ }
+ )
+ }
+
+ @Test
+ fun toggle_button_unselected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = false,
+ selectionControl = {
+ RadioButton(selected = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_checked_checkbox() = verifyScreenshot {
+ sampleToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_unchecked_checkbox() = verifyScreenshot {
+ sampleToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_checked_switch() = verifyScreenshot {
+ sampleToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_unchecked_switch() = verifyScreenshot {
+ sampleToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_selected_radio() = verifyScreenshot {
+ sampleToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_unselected_radio() = verifyScreenshot {
+ sampleToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_checked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_unchecked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_checked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_unchecked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_selected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_toggle_button_unselected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_checked_checkbox() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = true,
+ selectionControl = {
+ Checkbox(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_unchecked_checkbox() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = false,
+ selectionControl = {
+ Checkbox(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_checked_switch() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = true,
+ selectionControl = {
+ Switch(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_unchecked_switch() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = false,
+ selectionControl = {
+ Switch(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_selected_radio() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = true,
+ selectionControl = {
+ RadioButton(selected = true)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_unselected_radio() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = false,
+ selectionControl = {
+ RadioButton(selected = false)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_checked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = true,
+ selectionControl = {
+ Checkbox(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_unchecked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = false,
+ selectionControl = {
+ Checkbox(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_checked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = true,
+ selectionControl = {
+ Switch(checked = true)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_unchecked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = false,
+ selectionControl = {
+ Switch(checked = false)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_selected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = true,
+ selectionControl = {
+ RadioButton(selected = true)
+ }
+ )
+ }
+
+ @Test
+ fun split_toggle_button_unselected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = false,
+ selectionControl = {
+ RadioButton(selected = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_checked_checkbox() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_unchecked_checkbox() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_checked_switch() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_unchecked_switch() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_selected_radio() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_unselected_radio() = verifyScreenshot {
+ sampleSplitToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_checked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_unchecked_checkbox_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Checkbox(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_checked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_unchecked_switch_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ Switch(checked = false, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_selected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = true,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = true, enabled = false)
+ }
+ )
+ }
+
+ @Test
+ fun disabled_split_toggle_button_unselected_radio_rtl() =
+ verifyScreenshot(layoutDirection = LayoutDirection.Rtl) {
+ sampleSplitToggleButton(
+ checked = false,
+ enabled = false,
+ selectionControl = {
+ RadioButton(selected = false, enabled = false)
+ }
+ )
+ }
+
+ @Composable
+ private fun sampleToggleButton(
+ enabled: Boolean = true,
+ checked: Boolean = true,
+ selectionControl: @Composable () -> Unit = {
+ Checkbox(checked = checked)
+ },
+ ) {
+ ToggleButton(
+ icon = { TestIcon() },
+ label = {
+ Text("ToggleButton")
+ },
+ secondaryLabel = {
+ Text("Secondary label")
+ },
+ checked = checked,
+ enabled = enabled,
+ selectionControl = selectionControl,
+ onCheckedChange = {},
+ modifier = Modifier.testTag(TEST_TAG),
+ )
+ }
+
+ @Composable
+ private fun sampleSplitToggleButton(
+ checked: Boolean = true,
+ enabled: Boolean = true,
+ selectionControl: @Composable () -> Unit = {
+ }
+ ) {
+ SplitToggleButton(
+ label = {
+ Text("SplitToggleButton")
+ },
+ secondaryLabel = {
+ Text("Secondary label")
+ },
+ checked = checked,
+ enabled = enabled,
+ selectionControl = {
+ selectionControl()
+ },
+ onCheckedChange = {},
+ onClick = {},
+ modifier = Modifier.testTag(TEST_TAG),
+ )
+ }
+
+ private fun verifyScreenshot(
+ layoutDirection: LayoutDirection = LayoutDirection.Ltr,
+ content: @Composable () -> Unit
+ ) {
+ rule.setContentWithTheme {
+ CompositionLocalProvider(LocalLayoutDirection provides layoutDirection) {
+ content()
+ }
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertAgainstGolden(screenshotRule, testName.methodName)
+ }
+}
diff --git a/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ToggleButtonTest.kt b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ToggleButtonTest.kt
new file mode 100644
index 0000000..a9286c7
--- /dev/null
+++ b/wear/compose/compose-material3/src/androidTest/kotlin/androidx/wear/compose/material3/ToggleButtonTest.kt
@@ -0,0 +1,665 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.testutils.assertContainsColor
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.SemanticsProperties
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assert
+import androidx.compose.ui.test.assertHasClickAction
+import androidx.compose.ui.test.assertHeightIsAtLeast
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.captureToImage
+import androidx.compose.ui.test.isToggleable
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onChildAt
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import org.junit.Rule
+import org.junit.Test
+
+class ToggleButtonTest {
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun supports_testtag() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun split_button_supports_testtag() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertExists()
+ }
+
+ @Test
+ fun has_clickaction_when_enabled() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+ }
+
+ @Test
+ fun split_button_has_clickaction_when_enabled() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+ }
+
+ @Test
+ fun has_clickaction_when_disabled() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertHasClickAction()
+ }
+
+ @Test
+ fun split_button_has_clickaction_when_disabled() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+ }
+
+ @Test
+ fun is_toggleable() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNode(isToggleable()).assertExists()
+ }
+
+ @Test
+ fun split_button_is_toggleable() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNode(isToggleable()).assertExists()
+ }
+
+ @Test
+ fun split_button_is_clickable() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertHasClickAction()
+ }
+
+ @Test
+ fun is_correctly_enabled() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+ }
+
+ @Test
+ fun split_button_is_correctly_enabled() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsEnabled()
+ }
+
+ @Test
+ fun is_correctly_disabled() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsNotEnabled()
+ }
+
+ @Test
+ fun split_button_is_correctly_disabled() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0).assertIsNotEnabled()
+ }
+
+ @Test
+ fun is_on_when_checked() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ checked = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsOn()
+ }
+
+ @Test
+ fun split_button_is_on_when_checked() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ checked = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOn()
+ }
+
+ @Test
+ fun is_off_when_unchecked() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ checked = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).assertIsOff()
+ }
+
+ @Test
+ fun split_button_is_off_when_unchecked() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ checked = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(1).assertIsOff()
+ }
+
+ @Test
+ fun responds_to_toggle_on() {
+ rule.setContentWithTheme {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ ToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOff()
+ .performClick()
+ .assertIsOn()
+ }
+
+ @Test
+ fun split_button_responds_to_toggle_on() {
+ rule.setContentWithTheme {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .onChildAt(1)
+ .assertIsOff()
+ .performClick()
+ .assertIsOn()
+ }
+
+ @Test
+ fun responds_to_toggle_off() {
+ rule.setContentWithTheme {
+ val (checked, onCheckedChange) = remember { mutableStateOf(true) }
+ ToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOn()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun split_button_responds_to_toggle_off() {
+ rule.setContentWithTheme {
+ val (checked, onCheckedChange) = remember { mutableStateOf(true) }
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = true,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .onChildAt(1)
+ .assertIsOn()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun does_not_toggle_when_disabled() {
+ rule.setContentWithTheme {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ ToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .assertIsOff()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun split_button_does_not_toggle_when_disabled() {
+ rule.setContentWithTheme {
+ val (checked, onCheckedChange) = remember { mutableStateOf(false) }
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ enabled = false,
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule
+ .onNodeWithTag(TEST_TAG)
+ .onChildAt(1)
+ .assertIsOff()
+ .performClick()
+ .assertIsOff()
+ }
+
+ @Test
+ fun has_role_checkbox() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Checkbox
+ )
+ )
+ }
+
+ @Test
+ fun can_override_role() {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ modifier = Modifier
+ .testTag(TEST_TAG)
+ .semantics {
+ role = Role.Button
+ }
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Button
+ )
+ )
+ }
+
+ @Test
+ fun split_button_has_roles_button_and_checkbox() {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ modifier = Modifier.testTag(TEST_TAG)
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(0)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Button
+ )
+ )
+
+ rule.onNodeWithTag(TEST_TAG).onChildAt(1)
+ .assert(
+ SemanticsMatcher.expectValue(
+ SemanticsProperties.Role,
+ Role.Checkbox
+ )
+ )
+ }
+
+ @Test
+ fun displays_label_content() {
+ val textContent = "abc"
+
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ checked = true,
+ onCheckedChange = {},
+ label = {
+ Text(text = textContent)
+ }
+ )
+ }
+
+ rule.onNodeWithText(textContent).assertExists()
+ }
+
+ @Test
+ fun split_button_displays_label_content() {
+ val textContent = "abc"
+
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ checked = true,
+ onCheckedChange = {},
+ label = {
+ Text(text = textContent)
+ }
+ )
+ }
+
+ rule.onNodeWithText(textContent).assertExists()
+ }
+
+ @Test
+ fun toggle_button_hasAdjustableHeight() {
+ val minHeight: Dp = 53.dp
+
+ rule.setContentWithThemeForSizeAssertions {
+ ToggleButtonWithDefaults(
+ label = {
+ Text(
+ text = "ToggleButton text spanning over multiple lines of text " +
+ "to test height is adjustable. This should exceed the minimum height" +
+ " for the ToggleButton."
+ )
+ },
+ secondaryLabel = {
+ Text(
+ text = "Secondary label with text."
+ )
+ }
+ )
+ }.assertHeightIsAtLeast(minHeight)
+ }
+
+ @Test
+ fun split_toggle_button_hasAdjustableHeight() {
+ val minHeight: Dp = 53.dp
+
+ rule.setContentWithThemeForSizeAssertions {
+ ToggleButtonWithDefaults(
+ label = {
+ Text(
+ text = "Primary label with 3 lines of text."
+ )
+ },
+ secondaryLabel = {
+ Text(
+ text = "SplitToggleButton text spanning over multiple lines of text " +
+ "to test height is adjustable. This should exceed the minimum height" +
+ " for the SplitToggleButton."
+ )
+ }
+ )
+ }.assertHeightIsAtLeast(minHeight)
+ }
+
+ @Test
+ fun toggle_button_height_defaults_52dp() {
+ rule.setContentWithThemeForSizeAssertions {
+ ToggleButtonWithDefaults()
+ }.assertHeightIsEqualTo(52.dp)
+ }
+
+ @Test
+ fun split_toggle_button_height_defaults_52dp() {
+ rule.setContentWithThemeForSizeAssertions {
+ SplitToggleButtonWithDefaults()
+ }.assertHeightIsEqualTo(52.dp)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun toggle_button_allows_checked_background_color_override() =
+ verifyToggleButtonBackgroundColor(
+ checked = true,
+ enabled = true,
+ expectedColor = CHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun toggle_button_allows_unchecked_background_color_override() =
+ verifyToggleButtonBackgroundColor(
+ checked = false,
+ enabled = true,
+ expectedColor = UNCHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun split_toggle_button_allows_checked_background_color_override() =
+ verifySplitToggleButtonBackgroundColor(
+ checked = true,
+ enabled = true,
+ expectedColor = CHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ @Test
+ fun split_toggle_button_allows_unchecked_background_color_override() =
+ verifySplitToggleButtonBackgroundColor(
+ checked = false,
+ enabled = true,
+ expectedColor = UNCHECKED_COLOR
+ )
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun verifyToggleButtonBackgroundColor(
+ checked: Boolean,
+ enabled: Boolean,
+ expectedColor: Color
+ ) {
+ rule.setContentWithTheme {
+ ToggleButtonWithDefaults(
+ checked = checked,
+ colors = ToggleButtonDefaults.toggleButtonColors(
+ checkedContainerColor = CHECKED_COLOR,
+ uncheckedContainerColor = UNCHECKED_COLOR
+ ),
+ onCheckedChange = {},
+ enabled = enabled,
+ modifier = Modifier.testTag(TEST_TAG),
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertContainsColor(expectedColor)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun verifySplitToggleButtonBackgroundColor(
+ checked: Boolean,
+ enabled: Boolean,
+ expectedColor: Color
+ ) {
+ rule.setContentWithTheme {
+ SplitToggleButtonWithDefaults(
+ checked = checked,
+ colors = ToggleButtonDefaults.toggleButtonColors(
+ checkedContainerColor = CHECKED_COLOR,
+ uncheckedContainerColor = UNCHECKED_COLOR
+ ),
+ onCheckedChange = {},
+ enabled = enabled,
+ modifier = Modifier.testTag(TEST_TAG),
+ )
+ }
+
+ rule.onNodeWithTag(TEST_TAG)
+ .captureToImage()
+ .assertContainsColor(expectedColor)
+ }
+}
+
+@Composable
+private fun ToggleButtonWithDefaults(
+ modifier: Modifier = Modifier,
+ checked: Boolean = true,
+ enabled: Boolean = true,
+ colors: ToggleButtonColors = ToggleButtonDefaults.toggleButtonColors(),
+ onCheckedChange: (Boolean) -> Unit = {},
+ label: @Composable RowScope.() -> Unit = {
+ Text("Primary")
+ },
+ secondaryLabel: @Composable (RowScope.() -> Unit)? = null,
+ icon: @Composable (BoxScope.() -> Unit)? = null,
+ selectionControl: @Composable () -> Unit = {}
+) =
+ ToggleButton(
+ modifier = modifier,
+ checked = checked,
+ enabled = enabled,
+ colors = colors,
+ onCheckedChange = onCheckedChange,
+ label = label,
+ secondaryLabel = secondaryLabel,
+ icon = icon,
+ selectionControl = selectionControl
+ )
+
+@Composable
+private fun SplitToggleButtonWithDefaults(
+ modifier: Modifier = Modifier,
+ checked: Boolean = true,
+ enabled: Boolean = true,
+ colors: ToggleButtonColors = ToggleButtonDefaults.toggleButtonColors(),
+ onCheckedChange: (Boolean) -> Unit = {},
+ onClick: () -> Unit = {},
+ label: @Composable RowScope.() -> Unit = {
+ Text("Primary")
+ },
+ secondaryLabel: @Composable (RowScope.() -> Unit)? = null,
+ selectionControl: @Composable BoxScope.() -> Unit = {}
+) = SplitToggleButton(
+ modifier = modifier,
+ colors = colors,
+ checked = checked,
+ enabled = enabled,
+ onCheckedChange = onCheckedChange,
+ label = label,
+ secondaryLabel = secondaryLabel,
+ onClick = onClick,
+ selectionControl = selectionControl,
+)
+
+private val CHECKED_COLOR = Color(0xFFA020F0)
+private val UNCHECKED_COLOR = Color(0xFFFFA500)
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt
index b978a2b..a66faf1 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ContentAlpha.kt
@@ -15,6 +15,7 @@
*/
package androidx.wear.compose.material3
+import androidx.annotation.FloatRange
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf
@@ -83,9 +84,9 @@
*/
@Composable
private fun contentAlpha(
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
highContrastAlpha: Float,
- /*@FloatRange(from = 0.0, to = 1.0)*/
+ @FloatRange(from = 0.0, to = 1.0)
lowContrastAlpha: Float
): Float {
val contentColor = LocalContentColor.current
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Providers.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Providers.kt
index a8ad2b6..7ea28ed 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Providers.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Providers.kt
@@ -48,3 +48,35 @@
content()
}
}
+
+internal fun <T> provideNullableScopeContent(
+ contentColor: State<Color>,
+ textStyle: TextStyle,
+ content: (@Composable T.() -> Unit)?
+): (@Composable T.() -> Unit)? = content?.let {
+ {
+ val color = contentColor.value
+ CompositionLocalProvider(
+ LocalContentColor provides color,
+ LocalContentAlpha provides color.alpha,
+ LocalTextStyle provides textStyle
+ ) {
+ content()
+ }
+ }
+}
+
+internal fun <T> provideNullableScopeContent(
+ contentColor: State<Color>,
+ content: (@Composable T.() -> Unit)?
+): (@Composable T.() -> Unit)? = content?.let {
+ {
+ val color = contentColor.value
+ CompositionLocalProvider(
+ LocalContentColor provides color,
+ LocalContentAlpha provides color.alpha
+ ) {
+ content()
+ }
+ }
+}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SelectionControls.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SelectionControls.kt
index 128b9a5..c7bf76b 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SelectionControls.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/SelectionControls.kt
@@ -43,7 +43,7 @@
/**
* [Checkbox] provides an animated checkbox for use as a selection control in
- * [SelectionButton] or [SplitSelectionButton].
+ * [ToggleButton] or [SplitToggleButton].
*
* Checkbox sample:
* @sample androidx.wear.compose.material3.samples.CheckboxSample
@@ -56,7 +56,7 @@
* the color).
* @param onCheckedChange Callback to be invoked when Checkbox is clicked. If null, then this is
* passive and relies entirely on a higher-level component to control the state
- * (such as [SelectionButton] or [SplitSelectionButton]).
+ * (such as [ToggleButton] or [SplitToggleButton]).
* @param interactionSource When also providing [onCheckedChange], the [MutableInteractionSource]
* representing the stream of [Interaction]s for the "toggleable" tap area -
* can be used to customise the appearance / behavior of the Checkbox.
@@ -87,10 +87,11 @@
enabled = enabled,
onCheckedChange = onCheckedChange,
interactionSource = interactionSource,
- drawBox = { drawScope, color, progress ->
+ drawBox = { drawScope, color, progress, isRtl ->
drawScope.drawBox(
color = color,
- progress = progress
+ progress = progress,
+ isRtl = isRtl
)
},
progressAnimationSpec = PROGRESS_ANIMATION_SPEC,
@@ -100,7 +101,7 @@
/**
* [Switch] provides an animated switch for use as a selection control in
- * [SelectionButton] or [SplitSelectionButton].
+ * [ToggleButton] or [SplitToggleButton].
*
* Switch samples:
* @sample androidx.wear.compose.material3.samples.SwitchSample
@@ -115,7 +116,7 @@
* the color).
* @param onCheckedChange Callback to be invoked when Switch is clicked. If null, then this is
* passive and relies entirely on a higher-level component to control the state
- * (such as [SelectionButton] or [SplitSelectionButton]).
+ * (such as [ToggleButton] or [SplitToggleButton]).
* @param interactionSource When also providing [onCheckedChange], the [MutableInteractionSource]
* representing the stream of [Interaction]s for the "toggleable" tap area -
* can be used to customise the appearance / behavior of the Switch.
@@ -175,7 +176,7 @@
/**
* [RadioButton] provides an animated radio button for use as a selection control in
- * [SelectionButton] or [SplitSelectionButton].
+ * [ToggleButton] or [SplitToggleButton].
*
* RadioButton sample:
* @sample androidx.wear.compose.material3.samples.RadioButtonSample
@@ -188,7 +189,7 @@
* the color).
* @param onClick Callback to be invoked when RadioButton is clicked. If null, then this is
* passive and relies entirely on a higher-level component to control the state
- * (such as [SelectionButton] or [SplitSelectionButton]).
+ * (such as [ToggleButton] or [SplitToggleButton]).
* @param interactionSource When also providing [onClick], the [MutableInteractionSource]
* representing the stream of [Interaction]s for the "toggleable" tap area -
* can be used to customise the appearance / behavior of the RadioButton.
@@ -579,15 +580,15 @@
}
}
-private fun DrawScope.drawBox(color: Color, progress: Float) {
+private fun DrawScope.drawBox(color: Color, progress: Float, isRtl: Boolean) {
// Centering vertically.
val topCornerPx = (HEIGHT - BOX_SIZE).toPx() / 2
val strokeWidthPx = BOX_STROKE.toPx()
val halfStrokeWidthPx = strokeWidthPx / 2.0f
val radiusPx = BOX_RADIUS.toPx()
val checkboxSizePx = BOX_SIZE.toPx()
- // Aligning the box to the right.
- val startXOffsetPx = (WIDTH - HEIGHT).toPx()
+ // Aligning the box to the end.
+ val startXOffsetPx = if (isRtl) 0f else (WIDTH - HEIGHT).toPx()
// Draw the outline of the box.
drawRoundRect(
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ToggleButton.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ToggleButton.kt
new file mode 100644
index 0000000..fccda59
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ToggleButton.kt
@@ -0,0 +1,565 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.compose.material3
+
+import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.dp
+import androidx.wear.compose.materialcore.animateSelectionColor
+
+/**
+ * The Wear Material [ToggleButton] offers four slots and a specific layout for an icon, a
+ * label, a secondaryLabel and selection control. The icon and secondaryLabel are optional.
+ * The items are laid out in a row with the optional icon at the start, a column containing the two
+ * label slots in the middle and a slot for the selection control at the end.
+ *
+ * The [ToggleButton] is Stadium shaped and has a max height designed to take no more than
+ * two lines of text.
+ * With localisation and/or large font sizes, the [ToggleButton] height adjusts to
+ * accommodate the contents. The label and secondary label should be consistently aligned.
+ *
+ * Samples:
+ * Example of a ToggleButton with a Checkbox:
+ * @sample androidx.wear.compose.material3.samples.ToggleButtonWithCheckbox
+ *
+ * Example of a ToggleButton with a Switch:
+ * @sample androidx.wear.compose.material3.samples.ToggleButtonWithSwitch
+ *
+ * Example of a ToggleButton with a RadioButton:
+ * @sample androidx.wear.compose.material3.samples.ToggleButtonWithRadioButton
+ *
+ * [ToggleButton] can be enabled or disabled. A disabled button will not respond to click events.
+ *
+ * The recommended set of [SplitToggleButton] can be obtained from
+ * [ToggleButtonDefaults], e.g. [ToggleButtonDefaults.toggleButtonColors].
+ *
+ * @param checked Boolean flag indicating whether this button is currently checked.
+ * @param onCheckedChange Callback to be invoked when this buttons checked/selected status is changed.
+ * @param selectionControl A slot for providing the button's selection control.
+ * Three built-in types of selection control are supported: [Checkbox] ,[RadioButton], and [Switch].
+ * @param modifier Modifier to be applied to the [ToggleButton].
+ * @param enabled Controls the enabled state of the button. When `false`, this button will not
+ * be clickable.
+ * @param shape Defines the button's shape. It is strongly recommended to use the default as this
+ * shape is a key characteristic of the Wear Material Theme.
+ * @param colors [ToggleButtonColors] that will be used to resolve the background and
+ * content color for this button in different states.
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content.
+ * @param interactionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this button's "toggleable" tap area. You can create and pass in your own
+ * remembered [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this Chip in different [Interaction]s.
+ * @param icon An optional slot for providing an icon to indicate the purpose of the button. The
+ * contents are expected to be a horizontally and vertically center aligned icon of size
+ * 24.dp. In order to correctly render when the Chip is not enabled the
+ * icon must set its alpha value to [LocalContentAlpha].
+ * @param secondaryLabel A slot for providing the button's secondary label. The contents are expected
+ * to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if
+ * not. label and secondaryLabel contents should be consistently aligned.
+ * @param label A slot for providing the button's main label. The contents are expected to be text
+ * which is "start" aligned if there is an icon preset and "start" or "center" aligned if
+ * not. label and secondaryLabel contents should be consistently aligned.
+ */
+@Composable
+fun ToggleButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ selectionControl: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shape: Shape = MaterialTheme.shapes.large,
+ colors: ToggleButtonColors = ToggleButtonDefaults.toggleButtonColors(),
+ contentPadding: PaddingValues = ToggleButtonDefaults.ContentPadding,
+ interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ icon: @Composable (BoxScope.() -> Unit)? = null,
+ secondaryLabel: @Composable (RowScope.() -> Unit)? = null,
+ label: @Composable RowScope.() -> Unit
+) =
+ androidx.wear.compose.materialcore.ToggleButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ label = provideScopeContent(
+ contentColor = colors.contentColor(enabled = enabled, checked),
+ textStyle = MaterialTheme.typography.labelMedium,
+ content = label
+ ),
+ selectionControl = selectionControl,
+ modifier = modifier
+ .defaultMinSize(minHeight = MIN_HEIGHT)
+ .height(IntrinsicSize.Min),
+ icon = provideNullableScopeContent(
+ contentColor = colors.iconColor(enabled = enabled, checked),
+ content = icon
+ ),
+ secondaryLabel = provideNullableScopeContent(
+ contentColor = colors.secondaryContentColor(enabled = enabled, checked),
+ textStyle = MaterialTheme.typography.labelSmall,
+ content = secondaryLabel
+ ),
+ background = { isEnabled, isChecked ->
+ val backgroundColor =
+ colors.containerColor(enabled = isEnabled, checked = isChecked).value
+
+ Modifier.background(backgroundColor)
+ },
+ enabled = enabled,
+ interactionSource = interactionSource,
+ contentPadding = contentPadding,
+ shape = shape,
+ selectionControlWidth = SELECTION_CONTROL_WIDTH,
+ selectionControlHeight = SELECTION_CONTROL_HEIGHT
+ )
+
+/**
+ * The Wear Material [SplitToggleButton] offers three slots and a specific layout for a label,
+ * secondaryLabel and selection control. The secondaryLabel is optional. The items are laid out
+ * with a column containing the two label slots and a slot for the selection control at the
+ * end.
+ *
+ * The [SplitToggleButton] is Stadium shaped and has a max height designed to take no more than
+ * two lines of text.
+ * With localisation and/or large font sizes, the [SplitToggleButton] height adjusts to
+ * accommodate the contents. The label and secondary label should be consistently aligned.
+ *
+ * A [SplitToggleButton] has two tappable areas, one tap area for the labels and another for the
+ * toggle control. The [onClick] listener will be associated with the main body of the split toggle
+ * button with the [onCheckedChange] listener associated with the toggle control area only.
+ *
+ * Samples:
+ * Example of a SplitToggleButton with a Checkbox:
+ * @sample androidx.wear.compose.material3.samples.SplitToggleButtonWithCheckbox
+ *
+ * Example of a SplitToggleButton with a Switch:
+ * @sample androidx.wear.compose.material3.samples.SplitToggleButtonWithSwitch
+ *
+ * Example of a SplitToggleButton with a RadioButton:
+ * @sample androidx.wear.compose.material3.samples.SplitToggleButtonWithRadioButton
+ *
+ * For a SplitToggleButton the background of the tappable background area behind the selection control
+ * will have a visual effect applied to provide a "divider" between the two tappable areas.
+ *
+ * The recommended set of colors can be obtained from
+ * [ToggleButtonDefaults], e.g. [ToggleButtonDefaults.toggleButtonColors].
+ *
+ * [SplitToggleButton] can be enabled or disabled. A disabled button will not respond to click events.
+ *
+ * @param checked Boolean flag indicating whether this button is currently checked.
+ * @param onCheckedChange Callback to be invoked when this buttons checked/selected status is
+ * changed.
+ * @param onClick Click listener called when the user clicks the main body of the button, the area
+ * behind the labels.
+ * @param selectionControl A slot for providing the button's selection control.
+ * Three built-in types of selection control are supported: [Checkbox] ,[RadioButton], and [Switch].
+ * @param modifier Modifier to be applied to the button.
+ * @param enabled Controls the enabled state of the button. When `false`, this button will not
+ * be clickable.
+ * @param shape Defines the button's shape. It is strongly recommended to use the default as this
+ * shape is a key characteristic of the Wear Material Theme.
+ * @param colors [ToggleButtonColors] that will be used to resolve the background and
+ * content color for this button in different states.
+ * @param contentPadding The spacing values to apply internally between the container and the
+ * content.
+ * @param checkedInteractionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this button's "toggleable" tap area. You can create and pass in your own
+ * remembered [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this button in different [Interaction]s.
+ * @param clickInteractionSource The [MutableInteractionSource] representing the stream of
+ * [Interaction]s for this button's "clickable" tap area. You can create and pass in your own
+ * remembered [MutableInteractionSource] if you want to observe [Interaction]s and customize the
+ * appearance / behavior of this button in different [Interaction]s.
+ * @param secondaryLabel A slot for providing the button's secondary label. The contents are expected
+ * to be "start" or "center" aligned. label and secondaryLabel contents should be consistently
+ * aligned.
+ * @param label A slot for providing the button's main label. The contents are expected to be text
+ * which is "start" aligned if there is an icon preset and "start" or "center" aligned if
+ * not. label and secondaryLabel contents should be consistently aligned.
+ */
+@Composable
+fun SplitToggleButton(
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit,
+ onClick: () -> Unit,
+ selectionControl: @Composable BoxScope.() -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ shape: Shape = MaterialTheme.shapes.large,
+ colors: ToggleButtonColors = ToggleButtonDefaults.toggleButtonColors(),
+ checkedInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ clickInteractionSource: MutableInteractionSource = remember { MutableInteractionSource() },
+ contentPadding: PaddingValues = ToggleButtonDefaults.ContentPadding,
+ secondaryLabel: @Composable (RowScope.() -> Unit)? = null,
+ label: @Composable RowScope.() -> Unit
+) = androidx.wear.compose.materialcore.SplitToggleButton(
+ checked = checked,
+ onCheckedChange = onCheckedChange,
+ label = provideScopeContent(
+ contentColor = colors.contentColor(enabled = enabled, checked = checked),
+ textStyle = MaterialTheme.typography.labelMedium,
+ content = label
+ ),
+ onClick = onClick,
+ selectionControl = selectionControl,
+ modifier = modifier
+ .defaultMinSize(minHeight = MIN_HEIGHT)
+ .height(IntrinsicSize.Min),
+ secondaryLabel = provideNullableScopeContent(
+ contentColor = colors.secondaryContentColor(enabled = enabled, checked = checked),
+ textStyle = MaterialTheme.typography.labelSmall,
+ content = secondaryLabel
+ ),
+ backgroundColor = { isEnabled, isChecked ->
+ colors.containerColor(
+ enabled = isEnabled,
+ checked = isChecked
+ )
+ },
+ splitBackgroundColor = { isEnabled, isChecked ->
+ colors.splitContainerColor(
+ enabled = isEnabled,
+ checked = isChecked
+ )
+ },
+ enabled = enabled,
+ checkedInteractionSource = checkedInteractionSource,
+ clickInteractionSource = clickInteractionSource,
+ contentPadding = contentPadding,
+ shape = shape
+)
+
+/**
+ * Contains the default values used by [ToggleButton]s and [SplitToggleButton]s
+ */
+object ToggleButtonDefaults {
+
+ /**
+ * Creates a [ToggleButtonColors] for use in a [ToggleButton] and [SplitToggleButton].
+ *
+ * @param checkedContainerColor The container color of the [ToggleButton] or
+ * the [SplitToggleButton] when enabled and checked/selected.
+ * @param checkedContentColor The content color of the [ToggleButton]
+ * or the [SplitToggleButton] when enabled and checked/selected.
+ * @param checkedSecondaryContentColor The secondary content color of the [ToggleButton]
+ * or the [SplitToggleButton] when enabled and checked/selected,
+ * used for secondaryLabel content.
+ * @param checkedIconColor The icon color of the [ToggleButton]
+ * when enabled and checked/selected.
+ * @param checkedSplitContainerColor The split container color of the [SplitToggleButton]
+ * when enabled and checked/selected.
+ * @param uncheckedContainerColor The container color of the [ToggleButton]
+ * or the [SplitToggleButton] when enabled and unchecked/not selected.
+ * @param uncheckedContentColor The content color of a [ToggleButton]
+ * or the [SplitToggleButton] when enabled and unchecked/not selected.
+ * @param uncheckedSecondaryContentColor The secondary content color of this [ToggleButton]
+ * or the [SplitToggleButton] when enabled and unchecked/not selected,
+ * used for secondaryLabel content
+ * @param uncheckedIconColor The icon color of the [ToggleButton]
+ * when enabled and unchecked/not selected.
+ * @param uncheckedSplitContainerColor The split container color
+ * of the [SplitToggleButton] when enabled and unchecked/not selected.
+ */
+ @Composable
+ fun toggleButtonColors(
+ checkedContainerColor: Color = MaterialTheme.colorScheme.primaryContainer,
+ checkedContentColor: Color = MaterialTheme.colorScheme.onPrimaryContainer,
+ checkedSecondaryContentColor: Color = MaterialTheme.colorScheme.onPrimaryContainer.copy(
+ alpha = 0.8f
+ ),
+ checkedIconColor: Color = MaterialTheme.colorScheme.onPrimaryContainer,
+ checkedSplitContainerColor: Color = MaterialTheme.colorScheme.primary.copy(.15f),
+ uncheckedContainerColor: Color = MaterialTheme.colorScheme.surface,
+ uncheckedContentColor: Color = MaterialTheme.colorScheme.onSurface,
+ uncheckedSecondaryContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
+ uncheckedIconColor: Color = MaterialTheme.colorScheme.primary,
+ uncheckedSplitContainerColor: Color = MaterialTheme.colorScheme.surfaceBright
+ ) =
+ ToggleButtonColors(
+ checkedContainerColor = checkedContainerColor,
+ checkedContentColor = checkedContentColor,
+ checkedSecondaryContentColor = checkedSecondaryContentColor,
+ checkedIconColor = checkedIconColor,
+ checkedSplitContainerColor = checkedSplitContainerColor,
+ uncheckedContainerColor = uncheckedContainerColor,
+ uncheckedContentColor = uncheckedContentColor,
+ uncheckedSecondaryContentColor = uncheckedSecondaryContentColor,
+ uncheckedIconColor = uncheckedIconColor,
+ uncheckedSplitContainerColor = uncheckedSplitContainerColor,
+ disabledCheckedContainerColor = checkedContainerColor.toDisabledColor(),
+ disabledCheckedContentColor = checkedContentColor.toDisabledColor(),
+ disabledCheckedSecondaryContentColor = checkedSecondaryContentColor.toDisabledColor(),
+ disabledCheckedIconColor = checkedIconColor.toDisabledColor(),
+ disabledCheckedSplitContainerColor = checkedSplitContainerColor.toDisabledColor(),
+ disabledUncheckedContainerColor = uncheckedContainerColor.toDisabledColor(),
+ disabledUncheckedContentColor = uncheckedContentColor.toDisabledColor(),
+ disabledUncheckedSecondaryContentColor =
+ uncheckedSecondaryContentColor.toDisabledColor(),
+ disabledUncheckedIconColor = uncheckedIconColor.toDisabledColor(),
+ disabledUncheckedSplitContainerColor = uncheckedSplitContainerColor.toDisabledColor()
+ )
+
+ private val ChipHorizontalPadding = 14.dp
+ private val ChipVerticalPadding = 6.dp
+
+ val ContentPadding: PaddingValues = PaddingValues(
+ start = ChipHorizontalPadding,
+ top = ChipVerticalPadding,
+ end = ChipHorizontalPadding,
+ bottom = ChipVerticalPadding
+ )
+}
+
+/**
+ * Represents the different container and content colors used for toggle buttons
+ * ([ToggleButton], [IconToggleButton], and [TextToggleButton]) in various states,
+ * that are checked, unchecked, enabled and disabled.
+ */
+@Immutable
+class ToggleButtonColors constructor(
+ val checkedContainerColor: Color,
+ val checkedContentColor: Color,
+ val checkedSecondaryContentColor: Color,
+ val checkedIconColor: Color,
+ val checkedSplitContainerColor: Color,
+ val uncheckedContainerColor: Color,
+ val uncheckedContentColor: Color,
+ val uncheckedSecondaryContentColor: Color,
+ val uncheckedIconColor: Color,
+ val uncheckedSplitContainerColor: Color,
+ val disabledCheckedContainerColor: Color,
+ val disabledCheckedContentColor: Color,
+ val disabledCheckedSecondaryContentColor: Color,
+ val disabledCheckedIconColor: Color,
+ val disabledCheckedSplitContainerColor: Color,
+ val disabledUncheckedContainerColor: Color,
+ val disabledUncheckedContentColor: Color,
+ val disabledUncheckedSecondaryContentColor: Color,
+ val disabledUncheckedIconColor: Color,
+ val disabledUncheckedSplitContainerColor: Color,
+) {
+ constructor(
+ checkedContainerColor: Color,
+ checkedContentColor: Color,
+ uncheckedContainerColor: Color,
+ uncheckedContentColor: Color,
+ disabledCheckedContainerColor: Color,
+ disabledCheckedContentColor: Color,
+ disabledUncheckedContainerColor: Color,
+ disabledUncheckedContentColor: Color
+ ) : this(
+ checkedContainerColor = checkedContainerColor,
+ checkedContentColor = checkedContentColor,
+ checkedSecondaryContentColor = checkedContainerColor,
+ checkedIconColor = checkedContentColor,
+ checkedSplitContainerColor = checkedContentColor,
+ uncheckedContainerColor = uncheckedContainerColor,
+ uncheckedContentColor = uncheckedContentColor,
+ uncheckedSecondaryContentColor = uncheckedContentColor,
+ uncheckedIconColor = uncheckedContentColor,
+ uncheckedSplitContainerColor = uncheckedContainerColor,
+ disabledCheckedContainerColor = disabledCheckedContainerColor,
+ disabledCheckedContentColor = disabledCheckedContentColor,
+ disabledCheckedSecondaryContentColor = disabledCheckedContentColor,
+ disabledCheckedIconColor = disabledCheckedContentColor,
+ disabledCheckedSplitContainerColor = disabledCheckedContainerColor,
+ disabledUncheckedContainerColor = disabledUncheckedContainerColor,
+ disabledUncheckedContentColor = disabledUncheckedContentColor,
+ disabledUncheckedSecondaryContentColor = disabledUncheckedContentColor,
+ disabledUncheckedIconColor = disabledUncheckedContentColor,
+ disabledUncheckedSplitContainerColor = disabledUncheckedContainerColor,
+ )
+
+ /**
+ * Determines the container color based on whether the toggle button is [enabled]
+ * and [checked].
+ *
+ * @param enabled Whether the toggle button is enabled
+ * @param checked Whether the toggle button is checked
+ */
+ @Composable
+ fun containerColor(enabled: Boolean, checked: Boolean): State<Color> =
+ animateSelectionColor(
+ enabled = enabled,
+ checked = checked,
+ checkedColor = checkedContainerColor,
+ uncheckedColor = uncheckedContainerColor,
+ disabledCheckedColor = disabledCheckedContainerColor,
+ disabledUncheckedColor = disabledUncheckedContainerColor,
+ animationSpec = COLOR_ANIMATION_SPEC
+ )
+
+ /**
+ * Determines the content color based on whether the toggle button is [enabled]
+ * and [checked].
+ *
+ * @param enabled Whether the toggle button is enabled
+ * @param checked Whether the toggle button is checked
+ */
+ @Composable
+ fun contentColor(enabled: Boolean, checked: Boolean): State<Color> = animateSelectionColor(
+ enabled = enabled,
+ checked = checked,
+ checkedColor = checkedContentColor,
+ uncheckedColor = uncheckedContentColor,
+ disabledCheckedColor = disabledCheckedContentColor,
+ disabledUncheckedColor = disabledUncheckedContentColor,
+ animationSpec = COLOR_ANIMATION_SPEC
+ )
+
+ /**
+ * Represents the secondary content color depending on the [enabled] and [checked] properties.
+ *
+ * @param enabled Whether the ToggleButton is enabled.
+ * @param checked Whether the ToggleButton is currently checked/selected
+ * or unchecked/not selected.
+ */
+ @Composable
+ fun secondaryContentColor(enabled: Boolean, checked: Boolean): State<Color> =
+ animateSelectionColor(
+ enabled = enabled,
+ checked = checked,
+ checkedColor = checkedSecondaryContentColor,
+ uncheckedColor = uncheckedSecondaryContentColor,
+ disabledCheckedColor = disabledCheckedSecondaryContentColor,
+ disabledUncheckedColor = disabledUncheckedSecondaryContentColor,
+ animationSpec = COLOR_ANIMATION_SPEC
+ )
+
+ /**
+ * Represents the icon color for the [ToggleButton] depending on the
+ * [enabled] and [checked] properties.
+ *
+ * @param enabled Whether the ToggleButton is enabled.
+ * @param checked Whether the ToggleButton is currently checked/selected
+ * or unchecked/not selected.
+ */
+ @Composable
+ fun iconColor(enabled: Boolean, checked: Boolean): State<Color> =
+ animateSelectionColor(
+ enabled = enabled,
+ checked = checked,
+ checkedColor = checkedIconColor,
+ uncheckedColor = uncheckedIconColor,
+ disabledCheckedColor = disabledCheckedIconColor,
+ disabledUncheckedColor = disabledUncheckedIconColor,
+ animationSpec = COLOR_ANIMATION_SPEC
+ )
+
+ /**
+ * Represents the split container for the [SplitToggleButton] color depending on the
+ * [enabled] and [checked] properties.
+ *
+ * @param enabled Whether the SplitToggleButton is enabled.
+ * @param checked Whether the SplitToggleButton is currently checked/selected
+ * or unchecked/not selected.
+ */
+ @Composable
+ fun splitContainerColor(enabled: Boolean, checked: Boolean): State<Color> =
+ animateSelectionColor(
+ enabled = enabled,
+ checked = checked,
+ checkedColor = checkedSplitContainerColor,
+ uncheckedColor = uncheckedSplitContainerColor,
+ disabledCheckedColor = disabledCheckedSplitContainerColor,
+ disabledUncheckedColor = disabledUncheckedSplitContainerColor,
+ animationSpec = COLOR_ANIMATION_SPEC
+ )
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null) return false
+ if (this::class != other::class) return false
+
+ other as ToggleButtonColors
+
+ if (checkedContainerColor != other.checkedContainerColor) return false
+ if (checkedContentColor != other.checkedContentColor) return false
+ if (checkedSecondaryContentColor != other.checkedSecondaryContentColor) return false
+ if (checkedIconColor != other.checkedIconColor) return false
+ if (checkedSplitContainerColor != other.checkedSplitContainerColor) return false
+ if (uncheckedContainerColor != other.uncheckedContainerColor) return false
+ if (uncheckedContentColor != other.uncheckedContentColor) return false
+ if (uncheckedSecondaryContentColor != other.uncheckedSecondaryContentColor) return false
+ if (uncheckedIconColor != other.uncheckedIconColor) return false
+ if (uncheckedSplitContainerColor != other.uncheckedSplitContainerColor) return false
+ if (disabledCheckedContainerColor != other.disabledCheckedContainerColor) return false
+ if (disabledCheckedContentColor != other.disabledCheckedContentColor) return false
+ if (disabledCheckedSecondaryContentColor !=
+ other.disabledCheckedSecondaryContentColor
+ ) return false
+ if (disabledCheckedIconColor != other.disabledCheckedIconColor) return false
+ if (disabledCheckedSplitContainerColor != other.disabledCheckedSplitContainerColor)
+ return false
+ if (disabledUncheckedContainerColor != other.disabledUncheckedContainerColor) return false
+ if (disabledUncheckedContentColor != other.disabledUncheckedContentColor) return false
+ if (disabledUncheckedSecondaryContentColor !=
+ other.disabledUncheckedSecondaryContentColor
+ ) return false
+ if (disabledUncheckedIconColor != other.disabledUncheckedIconColor)
+ return false
+ if (disabledUncheckedSplitContainerColor != other.disabledUncheckedSplitContainerColor)
+ return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = checkedContainerColor.hashCode()
+ result = 31 * result + checkedContentColor.hashCode()
+ result = 31 * result + checkedSecondaryContentColor.hashCode()
+ result = 31 * result + checkedIconColor.hashCode()
+ result = 31 * result + checkedSplitContainerColor.hashCode()
+ result = 31 * result + uncheckedContainerColor.hashCode()
+ result = 31 * result + uncheckedContentColor.hashCode()
+ result = 31 * result + uncheckedSecondaryContentColor.hashCode()
+ result = 31 * result + uncheckedIconColor.hashCode()
+ result = 31 * result + uncheckedSplitContainerColor.hashCode()
+ result = 31 * result + disabledCheckedContainerColor.hashCode()
+ result = 31 * result + disabledCheckedContentColor.hashCode()
+ result = 31 * result + disabledCheckedSecondaryContentColor.hashCode()
+ result = 31 * result + disabledCheckedIconColor.hashCode()
+ result = 31 * result + disabledCheckedSplitContainerColor.hashCode()
+ result = 31 * result + disabledUncheckedContainerColor.hashCode()
+ result = 31 * result + disabledUncheckedContentColor.hashCode()
+ result = 31 * result + disabledUncheckedSecondaryContentColor.hashCode()
+ result = 31 * result + disabledUncheckedIconColor.hashCode()
+ result = 31 * result + disabledUncheckedSplitContainerColor.hashCode()
+ return result
+ }
+}
+
+private val SELECTION_CONTROL_WIDTH = 32.dp
+private val SELECTION_CONTROL_HEIGHT = 24.dp
+private val MIN_HEIGHT = 52.dp
+
+private val COLOR_ANIMATION_SPEC: AnimationSpec<Color> =
+ tween(MEDIUM_1, 0, STANDARD_DECELERATE)
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ToggleButtonColors.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ToggleButtonColors.kt
deleted file mode 100644
index c83f367..0000000
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/ToggleButtonColors.kt
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.wear.compose.material3
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.rememberUpdatedState
-import androidx.compose.ui.graphics.Color
-
-/**
- * Represents the different container and content colors used for toggle buttons
- * ([IconToggleButton] and [TextToggleButton]) in various states, that are checked, unchecked,
- * enabled and disabled.
- */
-@Immutable
-public class ToggleButtonColors public constructor(
- val checkedContainerColor: Color,
- val checkedContentColor: Color,
- val uncheckedContainerColor: Color,
- val uncheckedContentColor: Color,
- val disabledCheckedContainerColor: Color,
- val disabledCheckedContentColor: Color,
- val disabledUncheckedContainerColor: Color,
- val disabledUncheckedContentColor: Color,
-) {
-
- /**
- * Determines the container color based on whether the toggle button is [enabled]
- * and [checked].
- *
- * @param enabled Whether the toggle button is enabled
- * @param checked Whether the toggle button is checked
- */
- @Composable
- fun containerColor(enabled: Boolean, checked: Boolean): State<Color> {
- return rememberUpdatedState(
- if (enabled) {
- if (checked) checkedContainerColor else uncheckedContainerColor
- } else {
- if (checked) disabledCheckedContainerColor else disabledUncheckedContainerColor
- }
- )
- }
-
- /**
- * Determines the content color based on whether the toggle button is [enabled]
- * and [checked].
- *
- * @param enabled Whether the toggle button is enabled
- * @param checked Whether the toggle button is checked
- */
- @Composable
- fun contentColor(enabled: Boolean, checked: Boolean): State<Color> {
- return rememberUpdatedState(
- if (enabled) {
- if (checked) checkedContentColor else uncheckedContentColor
- } else {
- if (checked) disabledCheckedContentColor else disabledUncheckedContentColor
- }
- )
- }
-
- override fun equals(other: Any?): Boolean {
- if (this === other) return true
- if (other == null) return false
- if (this::class != other::class) return false
-
- other as ToggleButtonColors
-
- if (checkedContainerColor != other.checkedContainerColor) return false
- if (checkedContentColor != other.checkedContentColor) return false
- if (uncheckedContainerColor != other.uncheckedContainerColor) return false
- if (uncheckedContentColor != other.uncheckedContentColor) return false
- if (disabledCheckedContainerColor != other.disabledCheckedContainerColor) return false
- if (disabledCheckedContentColor != other.disabledCheckedContentColor) return false
- if (disabledUncheckedContainerColor != other.disabledUncheckedContainerColor) return false
- if (disabledUncheckedContentColor != other.disabledUncheckedContentColor) return false
-
- return true
- }
-
- override fun hashCode(): Int {
- var result = checkedContainerColor.hashCode()
- result = 31 * result + checkedContentColor.hashCode()
- result = 31 * result + uncheckedContainerColor.hashCode()
- result = 31 * result + uncheckedContentColor.hashCode()
- result = 31 * result + disabledCheckedContainerColor.hashCode()
- result = 31 * result + disabledCheckedContentColor.hashCode()
- result = 31 * result + disabledUncheckedContainerColor.hashCode()
- result = 31 * result + disabledUncheckedContentColor.hashCode()
- return result
- }
-}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt
index 8c3aaa1..341fc8d 100644
--- a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/Typography.kt
@@ -15,13 +15,15 @@
*/
package androidx.wear.compose.material3
+import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
+import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
+import androidx.wear.compose.material3.tokens.TypographyKeyTokens
+import androidx.wear.compose.material3.tokens.TypographyTokens
/**
* Class holding typography definitions as defined by the Wear Material typography specification.
@@ -95,84 +97,19 @@
) {
public constructor (
defaultFontFamily: FontFamily = FontFamily.Default,
- displayLarge: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Normal,
- fontSize = 40.sp,
- lineHeight = 44.sp,
- letterSpacing = 0.sp
- ),
- displayMedium: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Normal,
- fontSize = 30.sp,
- lineHeight = 34.sp,
- letterSpacing = 0.sp
- ),
- displaySmall: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 24.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.sp,
- ),
- titleLarge: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 20.sp,
- lineHeight = 22.sp,
- letterSpacing = 0.2.sp
- ),
- titleMedium: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 16.sp,
- lineHeight = 18.sp,
- letterSpacing = 0.3.sp
- ),
- titleSmall: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 14.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.3.sp
- ),
- labelLarge: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 20.sp,
- lineHeight = 22.sp,
- letterSpacing = 0.2.sp
- ),
- labelMedium: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 15.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.2.sp
- ),
- labelSmall: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 13.sp,
- lineHeight = 14.sp,
- letterSpacing = 0.3.sp
- ),
- bodyLarge: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Normal,
- fontSize = 16.sp,
- lineHeight = 18.sp,
- letterSpacing = 0.3.sp,
- ),
- bodyMedium: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Normal,
- fontSize = 14.sp,
- lineHeight = 18.sp,
- letterSpacing = 0.2.sp
- ),
- bodySmall: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Medium,
- fontSize = 12.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.4.sp
- ),
- bodyExtraSmall: TextStyle = DefaultTextStyle.copy(
- fontWeight = FontWeight.Normal,
- fontSize = 11.sp,
- lineHeight = 14.sp,
- letterSpacing = 0.4.sp
- )
+ displayLarge: TextStyle = TypographyTokens.DisplayLarge,
+ displayMedium: TextStyle = TypographyTokens.DisplayMedium,
+ displaySmall: TextStyle = TypographyTokens.DisplaySmall,
+ titleLarge: TextStyle = TypographyTokens.TitleLarge,
+ titleMedium: TextStyle = TypographyTokens.TitleMedium,
+ titleSmall: TextStyle = TypographyTokens.TitleSmall,
+ labelLarge: TextStyle = TypographyTokens.LabelLarge,
+ labelMedium: TextStyle = TypographyTokens.LabelMedium,
+ labelSmall: TextStyle = TypographyTokens.LabelSmall,
+ bodyLarge: TextStyle = TypographyTokens.BodyLarge,
+ bodyMedium: TextStyle = TypographyTokens.BodyMedium,
+ bodySmall: TextStyle = TypographyTokens.BodySmall,
+ bodyExtraSmall: TextStyle = TypographyTokens.BodyExtraSmall
) : this(
displayLarge = displayLarge.withDefaultFontFamily(defaultFontFamily),
displayMedium = displayMedium.withDefaultFontFamily(defaultFontFamily),
@@ -289,6 +226,36 @@
)
/**
+ * Helper function for typography tokens.
+ */
+internal fun Typography.fromToken(value: TypographyKeyTokens): TextStyle {
+ return when (value) {
+ TypographyKeyTokens.DisplayLarge -> displayLarge
+ TypographyKeyTokens.DisplayMedium -> displayMedium
+ TypographyKeyTokens.DisplaySmall -> displaySmall
+ TypographyKeyTokens.TitleLarge -> titleLarge
+ TypographyKeyTokens.TitleMedium -> titleMedium
+ TypographyKeyTokens.TitleSmall -> titleSmall
+ TypographyKeyTokens.LabelLarge -> labelLarge
+ TypographyKeyTokens.LabelMedium -> labelMedium
+ TypographyKeyTokens.LabelSmall -> labelSmall
+ TypographyKeyTokens.BodyLarge -> bodyLarge
+ TypographyKeyTokens.BodyMedium -> bodyMedium
+ TypographyKeyTokens.BodySmall -> bodySmall
+ TypographyKeyTokens.BodyExtraSmall -> bodyExtraSmall
+ }
+}
+
+/**
+ * Helper function to convert [TypographyKeyTokens] to [TextStyle].
+ */
+@Composable
+@ReadOnlyComposable
+internal fun TypographyKeyTokens.toTextStyle(): TextStyle {
+ return MaterialTheme.typography.fromToken(this)
+}
+
+/**
* This Ambient holds on to the current definition of typography for this application as described
* by the Wear Material spec. You can read the values in it when creating custom components that
* want to use Wear Material types, as well as override the values when you want to re-style a part
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt
new file mode 100644
index 0000000..2eea3e2
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypefaceTokens.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// VERSION: v0_8
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+
+internal object TypefaceTokens {
+ val Brand = FontFamily.SansSerif
+ val MediumWeight = FontWeight.Medium
+ val Plain = FontFamily.SansSerif
+ val RegularWeight = FontWeight.Normal
+ val WeightBold = FontWeight.Bold
+}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypescaleTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypescaleTokens.kt
new file mode 100644
index 0000000..858bbf7
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypescaleTokens.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// VERSION: v0_9
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+import androidx.compose.ui.unit.sp
+
+internal object TypeScaleTokens {
+ val BodyExtraSmallFont = TypefaceTokens.Brand
+ val BodyExtraSmallLineHeight = 14.0.sp
+ val BodyExtraSmallSize = 11.sp
+ val BodyExtraSmallTracking = 0.4.sp
+ val BodyExtraSmallWeight = TypefaceTokens.RegularWeight
+ val BodyExtraSmallWeightProminent = TypefaceTokens.WeightBold
+ val BodyLargeFont = TypefaceTokens.Brand
+ val BodyLargeLineHeight = 18.0.sp
+ val BodyLargeSize = 16.sp
+ val BodyLargeTracking = 0.3.sp
+ val BodyLargeWeight = TypefaceTokens.RegularWeight
+ val BodyLargeWeightProminent = TypefaceTokens.WeightBold
+ val BodyMediumFont = TypefaceTokens.Brand
+ val BodyMediumLineHeight = 18.0.sp
+ val BodyMediumSize = 14.sp
+ val BodyMediumTracking = 0.2.sp
+ val BodyMediumWeight = TypefaceTokens.RegularWeight
+ val BodyMediumWeightProminent = TypefaceTokens.WeightBold
+ val BodySmallFont = TypefaceTokens.Brand
+ val BodySmallLineHeight = 16.0.sp
+ val BodySmallSize = 12.sp
+ val BodySmallTracking = 0.4.sp
+ val BodySmallWeight = TypefaceTokens.MediumWeight
+ val BodySmallWeightProminent = TypefaceTokens.WeightBold
+ val DisplayLargeFont = TypefaceTokens.Brand
+ val DisplayLargeLineHeight = 44.0.sp
+ val DisplayLargeSize = 40.sp
+ val DisplayLargeTracking = 0.0.sp
+ val DisplayLargeWeight = TypefaceTokens.RegularWeight
+ val DisplayMediumFont = TypefaceTokens.Brand
+ val DisplayMediumLineHeight = 34.0.sp
+ val DisplayMediumSize = 30.sp
+ val DisplayMediumTracking = 0.0.sp
+ val DisplayMediumWeight = TypefaceTokens.RegularWeight
+ val DisplaySmallFont = TypefaceTokens.Brand
+ val DisplaySmallLineHeight = 28.0.sp
+ val DisplaySmallSize = 24.sp
+ val DisplaySmallTracking = 0.0.sp
+ val DisplaySmallWeight = TypefaceTokens.MediumWeight
+ val LabelLargeFont = TypefaceTokens.Brand
+ val LabelLargeLineHeight = 22.0.sp
+ val LabelLargeSize = 20.sp
+ val LabelLargeTracking = 0.2.sp
+ val LabelLargeWeight = TypefaceTokens.MediumWeight
+ val LabelMediumFont = TypefaceTokens.Brand
+ val LabelMediumLineHeight = 16.0.sp
+ val LabelMediumSize = 15.sp
+ val LabelMediumTracking = 0.2.sp
+ val LabelMediumWeight = TypefaceTokens.MediumWeight
+ val LabelSmallFont = TypefaceTokens.Brand
+ val LabelSmallLineHeight = 14.0.sp
+ val LabelSmallSize = 13.sp
+ val LabelSmallTracking = 0.3.sp
+ val LabelSmallWeight = TypefaceTokens.MediumWeight
+ val TitleLargeFont = TypefaceTokens.Brand
+ val TitleLargeLineHeight = 22.0.sp
+ val TitleLargeSize = 20.sp
+ val TitleLargeTracking = 0.2.sp
+ val TitleLargeWeight = TypefaceTokens.MediumWeight
+ val TitleMediumFont = TypefaceTokens.Brand
+ val TitleMediumLineHeight = 18.0.sp
+ val TitleMediumSize = 16.sp
+ val TitleMediumTracking = 0.3.sp
+ val TitleMediumWeight = TypefaceTokens.MediumWeight
+ val TitleSmallFont = TypefaceTokens.Brand
+ val TitleSmallLineHeight = 16.0.sp
+ val TitleSmallSize = 14.sp
+ val TitleSmallTracking = 0.3.sp
+ val TitleSmallWeight = TypefaceTokens.MediumWeight
+}
diff --git a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
similarity index 62%
copy from core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
copy to wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
index 9914490..40869af 100644
--- a/core/core-performance/src/test/java/androidx/core/performance/DevicePerformanceTest.kt
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyKeyTokens.kt
@@ -14,17 +14,23 @@
* limitations under the License.
*/
-package androidx.core.performance
+// VERSION: v0_8
+// GENERATED CODE - DO NOT MODIFY BY HAND
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
+package androidx.wear.compose.material3.tokens
-/** Unit tests for [DevicePerformance]. */
-class DevicePerformanceTest {
-
- @Test
- fun mediaPerformanceClass() {
- // TODO: b/289279260 - Correctly handle threads in tests without leaking.
- assertThat(true).isEqualTo(true)
- }
+internal enum class TypographyKeyTokens {
+ BodyExtraSmall,
+ BodyLarge,
+ BodyMedium,
+ BodySmall,
+ DisplayLarge,
+ DisplayMedium,
+ DisplaySmall,
+ LabelLarge,
+ LabelMedium,
+ LabelSmall,
+ TitleLarge,
+ TitleMedium,
+ TitleSmall,
}
diff --git a/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt
new file mode 100644
index 0000000..60131a2
--- /dev/null
+++ b/wear/compose/compose-material3/src/main/java/androidx/wear/compose/material3/tokens/TypographyTokens.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// VERSION: v0_8
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+package androidx.wear.compose.material3.tokens
+
+import androidx.wear.compose.material3.DefaultTextStyle
+
+internal object TypographyTokens {
+ val BodyExtraSmall =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.BodyExtraSmallFont,
+ fontWeight = TypeScaleTokens.BodyExtraSmallWeight,
+ fontSize = TypeScaleTokens.BodyExtraSmallSize,
+ lineHeight = TypeScaleTokens.BodyExtraSmallLineHeight,
+ letterSpacing = TypeScaleTokens.BodyExtraSmallTracking,
+ )
+ val BodyLarge =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.BodyLargeFont,
+ fontWeight = TypeScaleTokens.BodyLargeWeight,
+ fontSize = TypeScaleTokens.BodyLargeSize,
+ lineHeight = TypeScaleTokens.BodyLargeLineHeight,
+ letterSpacing = TypeScaleTokens.BodyLargeTracking,
+ )
+ val BodyMedium =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.BodyMediumFont,
+ fontWeight = TypeScaleTokens.BodyMediumWeight,
+ fontSize = TypeScaleTokens.BodyMediumSize,
+ lineHeight = TypeScaleTokens.BodyMediumLineHeight,
+ letterSpacing = TypeScaleTokens.BodyMediumTracking,
+ )
+ val BodySmall =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.BodySmallFont,
+ fontWeight = TypeScaleTokens.BodySmallWeight,
+ fontSize = TypeScaleTokens.BodySmallSize,
+ lineHeight = TypeScaleTokens.BodySmallLineHeight,
+ letterSpacing = TypeScaleTokens.BodySmallTracking,
+ )
+ val DisplayLarge =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.DisplayLargeFont,
+ fontWeight = TypeScaleTokens.DisplayLargeWeight,
+ fontSize = TypeScaleTokens.DisplayLargeSize,
+ lineHeight = TypeScaleTokens.DisplayLargeLineHeight,
+ letterSpacing = TypeScaleTokens.DisplayLargeTracking,
+ )
+ val DisplayMedium =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.DisplayMediumFont,
+ fontWeight = TypeScaleTokens.DisplayMediumWeight,
+ fontSize = TypeScaleTokens.DisplayMediumSize,
+ lineHeight = TypeScaleTokens.DisplayMediumLineHeight,
+ letterSpacing = TypeScaleTokens.DisplayMediumTracking,
+ )
+ val DisplaySmall =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.DisplaySmallFont,
+ fontWeight = TypeScaleTokens.DisplaySmallWeight,
+ fontSize = TypeScaleTokens.DisplaySmallSize,
+ lineHeight = TypeScaleTokens.DisplaySmallLineHeight,
+ letterSpacing = TypeScaleTokens.DisplaySmallTracking,
+ )
+ val LabelLarge =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.LabelLargeFont,
+ fontWeight = TypeScaleTokens.LabelLargeWeight,
+ fontSize = TypeScaleTokens.LabelLargeSize,
+ lineHeight = TypeScaleTokens.LabelLargeLineHeight,
+ letterSpacing = TypeScaleTokens.LabelLargeTracking,
+ )
+ val LabelMedium =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.LabelMediumFont,
+ fontWeight = TypeScaleTokens.LabelMediumWeight,
+ fontSize = TypeScaleTokens.LabelMediumSize,
+ lineHeight = TypeScaleTokens.LabelMediumLineHeight,
+ letterSpacing = TypeScaleTokens.LabelMediumTracking,
+ )
+ val LabelSmall =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.LabelSmallFont,
+ fontWeight = TypeScaleTokens.LabelSmallWeight,
+ fontSize = TypeScaleTokens.LabelSmallSize,
+ lineHeight = TypeScaleTokens.LabelSmallLineHeight,
+ letterSpacing = TypeScaleTokens.LabelSmallTracking,
+ )
+ val TitleLarge =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.TitleLargeFont,
+ fontWeight = TypeScaleTokens.TitleLargeWeight,
+ fontSize = TypeScaleTokens.TitleLargeSize,
+ lineHeight = TypeScaleTokens.TitleLargeLineHeight,
+ letterSpacing = TypeScaleTokens.TitleLargeTracking,
+ )
+ val TitleMedium =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.TitleMediumFont,
+ fontWeight = TypeScaleTokens.TitleMediumWeight,
+ fontSize = TypeScaleTokens.TitleMediumSize,
+ lineHeight = TypeScaleTokens.TitleMediumLineHeight,
+ letterSpacing = TypeScaleTokens.TitleMediumTracking,
+ )
+ val TitleSmall =
+ DefaultTextStyle.copy(
+ fontFamily = TypeScaleTokens.TitleSmallFont,
+ fontWeight = TypeScaleTokens.TitleSmallWeight,
+ fontSize = TypeScaleTokens.TitleSmallSize,
+ lineHeight = TypeScaleTokens.TitleSmallLineHeight,
+ letterSpacing = TypeScaleTokens.TitleSmallTracking,
+ )
+}
diff --git a/wear/compose/integration-tests/demos/build.gradle b/wear/compose/integration-tests/demos/build.gradle
index 36e7808d..892fc54 100644
--- a/wear/compose/integration-tests/demos/build.gradle
+++ b/wear/compose/integration-tests/demos/build.gradle
@@ -50,6 +50,8 @@
implementation("androidx.wear:wear:1.1.0")
+ implementation("androidx.tracing:tracing:1.1.0")
+
implementation(project(":compose:foundation:foundation"))
implementation(project(":compose:foundation:foundation-layout"))
implementation(project(":compose:integration-tests:demos:common"))
diff --git a/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
index 646addf..0e3f0ea 100644
--- a/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
+++ b/wear/compose/integration-tests/demos/src/androidTest/java/androidx/wear/compose/integration/demos/test/DemoTest.kt
@@ -16,6 +16,7 @@
package androidx.wear.compose.integration.demos.test
+import android.util.Log
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.SemanticsNodeInteractionCollection
import androidx.compose.ui.test.hasClickAction
@@ -33,15 +34,19 @@
import androidx.wear.compose.integration.demos.common.Demo
import androidx.wear.compose.integration.demos.common.DemoCategory
import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
private val ignoredDemos = listOf<String>(
- // Not ignoring any of them \o/
+ // TODO(b/294013164): Reinstate these tests
+ "Material > Curved Text > Basic Styling",
+ "Material > Curved Text > Provider Styling",
)
+// Run this test on a phone emulator.
+// There are issues running on Watch emulators that menu items off screen are not found,
+// given the use of ScalingLAZYColumn.
@LargeTest
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalTestApi::class)
@@ -50,7 +55,6 @@
@get:Rule
val rule = createAndroidComposeRule<DemoActivity>()
- @Ignore("b/276935528")
@Test
fun navigateThroughAllDemos() {
// Compose integration-tests are split into batches due to size,
@@ -102,6 +106,7 @@
path: List<DemoCategory>,
fastForwardClock: Boolean
) {
+ Log.d("TEST", "Visit ${this.navigationTitle(path)}")
if (fastForwardClock) {
// Skip through the enter animation of the list screen
fastForwardClock()
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PlaceholderDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PlaceholderDemo.kt
index 0bca8a9..0a9a684 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PlaceholderDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/PlaceholderDemo.kt
@@ -16,7 +16,9 @@
package androidx.wear.compose.integration.demos
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Spacer
@@ -30,6 +32,7 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -38,10 +41,12 @@
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
+import androidx.wear.compose.integration.demos.common.Centralize
import androidx.wear.compose.material.AppCard
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.ChipColors
import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.CompactChip
import androidx.wear.compose.material.ExperimentalWearMaterialApi
import androidx.wear.compose.material.ListHeader
import androidx.wear.compose.material.MaterialTheme
@@ -54,303 +59,283 @@
@Composable
fun PlaceholderChips() {
- ScalingLazyColumnWithRSB {
- item {
- ListHeader {
- Text(text = "Primary Label Center Aligned", textAlign = TextAlign.Center)
+ var resetCount by remember { mutableIntStateOf(0) }
+ Box {
+ ScalingLazyColumnWithRSB {
+ item {
+ ListHeader {
+ Text(text = "Primary Label Center Aligned", textAlign = TextAlign.Center)
+ }
+ }
+
+ item {
+ var labelText by remember { mutableStateOf("") }
+ ChipWithContentPlaceholders(
+ label = labelText,
+ textAlignment = TextAlign.Center
+ )
+ LaunchedEffect(resetCount) {
+ labelText = ""
+ delay(3000)
+ labelText = "Primary Label"
+ }
+ }
+ item {
+ var labelText by remember { mutableStateOf("") }
+ ChipWithContentPlaceholders(
+ label = labelText,
+ textAlignment = TextAlign.Center,
+ colors = ChipDefaults.primaryChipColors()
+ )
+ LaunchedEffect(resetCount) {
+ labelText = ""
+ delay(3000)
+ labelText = "Primary Label"
+ }
+ }
+ item {
+ var labelText by remember { mutableStateOf("") }
+ ChipWithContentPlaceholders(
+ label = labelText,
+ textAlignment = TextAlign.Center,
+ colors = ChipDefaults.gradientBackgroundChipColors()
+ )
+ LaunchedEffect(resetCount) {
+ labelText = ""
+ delay(3000)
+ labelText = "Primary Label"
+ }
+ }
+ item {
+ var labelText by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = labelText,
+ textAlignment = TextAlign.Center
+ )
+ LaunchedEffect(resetCount) {
+ labelText = ""
+ delay(3000)
+ labelText = "Primary Label Center"
+ }
+ }
+
+ item {
+ ListHeader {
+ Text(text = "Primary Label Left Aligned", textAlign = TextAlign.Center)
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ delay(3000)
+ label = "Primary Label"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ delay(3000)
+ label =
+ "Primary that is long, to show truncation, we shouldn't be able to see " +
+ "more than 2 lines"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ icon = R.drawable.ic_accessibility_24px,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ delay(3000)
+ label = "Primary Label with icon"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ icon = R.drawable.ic_accessibility_24px,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ delay(3000)
+ label =
+ "Primary that is long, to show truncation, we shouldn't be able to see " +
+ "more than 2 lines"
+ }
+ }
+ item {
+ ListHeader {
+ Text(text = "Primary + Secondary Label", textAlign = TextAlign.Center)
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ var secondaryLabel by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ secondaryLabel = secondaryLabel,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ secondaryLabel = ""
+ delay(3000)
+ label = "Primary Label"
+ secondaryLabel = "Secondary Label"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ var secondaryLabel by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ secondaryLabel = secondaryLabel,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ secondaryLabel = ""
+ delay(3000)
+ label =
+ "Primary that is long, to show truncation, we shouldn't be able to see " +
+ "more than 1 line"
+ secondaryLabel = "Secondary Label"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ var secondaryLabel by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ icon = R.drawable.ic_accessibility_24px,
+ secondaryLabel = secondaryLabel,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ secondaryLabel = ""
+ delay(3000)
+ label = "Primary Label with icon"
+ secondaryLabel = "Secondary Label"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ icon = R.drawable.ic_accessibility_24px,
+ colors = ChipDefaults.chipColors(
+ backgroundColor = MaterialTheme.colors.surface,
+ iconColor = AlternatePrimaryColor2.copy(alpha = 0.5f),
+ ),
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ delay(3000)
+ label = "Primary Label with icon"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ var secondaryLabel by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ icon = R.drawable.ic_accessibility_24px,
+ secondaryLabel = secondaryLabel,
+ colors = ChipDefaults.chipColors(
+ backgroundColor = AlternatePrimaryColor2
+ ),
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ secondaryLabel = ""
+ delay(3000)
+ label = "Primary Label with icon"
+ secondaryLabel = "Content color override"
+ }
+ }
+ item {
+ var label by remember { mutableStateOf("") }
+ var secondaryLabel by remember { mutableStateOf("") }
+ ChipWithOverlaidPlaceholder(
+ label = label,
+ icon = R.drawable.ic_accessibility_24px,
+ secondaryLabel = secondaryLabel,
+ )
+ LaunchedEffect(resetCount) {
+ label = ""
+ secondaryLabel = ""
+ delay(3000)
+ label =
+ "Primary that is long, to show truncation, we shouldn't be able to see " +
+ "more than 1 line"
+ secondaryLabel = "Long Secondary that is long, to show truncation, we " +
+ "shouldn't be able to see more than 1 line"
+ }
}
}
- item {
- var labelText by remember { mutableStateOf("") }
- ChipWithContentPlaceholders(
- label = labelText,
- textAlignment = TextAlign.Center
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.Bottom,
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ CompactChip(
+ label = { Text("Reset") },
+ onClick = { resetCount++ }
)
- LaunchedEffect(Unit) {
- delay(3000)
- labelText = "Primary Label"
- }
- }
- item {
- var labelText by remember { mutableStateOf("") }
- ChipWithContentPlaceholders(
- label = labelText,
- textAlignment = TextAlign.Center,
- colors = ChipDefaults.primaryChipColors()
- )
- LaunchedEffect(Unit) {
- delay(3000)
- labelText = "Primary Label"
- }
- }
- item {
- var labelText by remember { mutableStateOf("") }
- ChipWithContentPlaceholders(
- label = labelText,
- textAlignment = TextAlign.Center,
- colors = ChipDefaults.gradientBackgroundChipColors()
- )
- LaunchedEffect(Unit) {
- delay(3000)
- labelText = "Primary Label"
- }
- }
- item {
- var labelText by remember { mutableStateOf("") }
- ChipWithContentPlaceholders(
- label = labelText,
- textAlignment = TextAlign.Center,
- )
- LaunchedEffect(Unit) {
- delay(3000)
- labelText = "Primary Label"
- }
- }
- item {
- var labelText by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = labelText,
- textAlignment = TextAlign.Center
- )
- LaunchedEffect(Unit) {
- delay(3000)
- labelText = "Primary Label Center"
- }
- }
- item {
- var labelText by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = labelText,
- textAlignment = TextAlign.Center
- )
- LaunchedEffect(Unit) {
- delay(3000)
- labelText = "Primary Label Center"
- }
- }
-
- item {
- ListHeader {
- Text(text = "Primary Label Left Aligned", textAlign = TextAlign.Center)
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label = "Primary Label"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label =
- "Primary that is long, to show truncation, we shouldn't be able to see " +
- "more than 2 lines"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- icon = R.drawable.ic_accessibility_24px,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label = "Primary Label with icon"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- icon = R.drawable.ic_accessibility_24px,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label =
- "Primary that is long, to show truncation, we shouldn't be able to see " +
- "more than 2 lines"
- }
- }
- item {
- ListHeader {
- Text(text = "Primary + Secondary Label", textAlign = TextAlign.Center)
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- var secondaryLabel by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- secondaryLabel = secondaryLabel,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label = "Primary Label"
- secondaryLabel = "Secondary Label"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- var secondaryLabel by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- secondaryLabel = secondaryLabel,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label =
- "Primary that is long, to show truncation, we shouldn't be able to see " +
- "more than 1 line"
- secondaryLabel = "Secondary Label"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- var secondaryLabel by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- icon = R.drawable.ic_accessibility_24px,
- secondaryLabel = secondaryLabel,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label = "Primary Label with icon"
- secondaryLabel = "Secondary Label"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- icon = R.drawable.ic_accessibility_24px,
- colors = ChipDefaults.chipColors(
- backgroundColor = MaterialTheme.colors.surface,
- iconColor = AlternatePrimaryColor2.copy(alpha = 0.5f),
- ),
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label = "Primary Label with icon"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- var secondaryLabel by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- icon = R.drawable.ic_accessibility_24px,
- secondaryLabel = secondaryLabel,
- colors = ChipDefaults.chipColors(
- backgroundColor = AlternatePrimaryColor2
- ),
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label = "Primary Label with icon"
- secondaryLabel = "Content color override"
- }
- }
- item {
- var label by remember { mutableStateOf("") }
- var secondaryLabel by remember { mutableStateOf("") }
- ChipWithOverlaidPlaceholder(
- label = label,
- icon = R.drawable.ic_accessibility_24px,
- secondaryLabel = secondaryLabel,
- )
- LaunchedEffect(key1 = Unit) {
- delay(3000)
- label =
- "Primary that is long, to show truncation, we shouldn't be able to see " +
- "more than 1 line"
- secondaryLabel = "Long Secondary that is long, to show truncation, we " +
- "shouldn't be able to see more than 1 line"
- }
}
}
}
@Composable
fun PlaceholderCards() {
+ var resetCount by remember { mutableIntStateOf(0) }
+ var refreshCount by remember { mutableIntStateOf(0) }
+ val showContent = remember { Array(4) { mutableStateOf(false) } }
+
+ LaunchedEffect(resetCount) {
+ showContent.forEach { it.value = false }
+ delay(4000)
+ refreshCount++
+ showContent.forEach {
+ it.value = true
+ delay(300)
+ }
+ }
+
ScalingLazyColumnWithRSB {
item {
ListHeader {
- Text("Overlaid Placeholders")
+ Text("Overlaid Placeholders", textAlign = TextAlign.Center)
}
}
item {
- var showContent by remember { mutableStateOf(false) }
- CardWithOverlaidPlaceholder(
- contentReady = { showContent },
- content = if (showContent) {
- {
- Text("Some content")
- Text("Some more content")
- }
- } else null
- )
- LaunchedEffect(Unit) {
- delay(2000)
- showContent = true
+ Centralize {
+ Chip(
+ label = { Text("Reset") },
+ onClick = { resetCount++ }
+ )
}
}
- item {
- var showContent by remember { mutableStateOf(false) }
- CardWithOverlaidPlaceholder(
- contentReady = { showContent },
- content = if (showContent) {
+ repeat(4) { itemIndex ->
+ item {
+ CardWithOverlaidPlaceholder(
+ contentReady = { showContent[itemIndex].value },
+ content =
{
- Text("Some content")
+ Text("Some content $refreshCount")
Text("Some more content")
}
- } else null
- )
- LaunchedEffect(Unit) {
- delay(2000)
- showContent = true
- }
- }
-
- item {
- var showContent by remember { mutableStateOf(false) }
- CardWithOverlaidPlaceholder(
- contentReady = { showContent },
- content = if (showContent) {
- {
- Text("Some content")
- Text("Some more content")
- }
- } else null
- )
- LaunchedEffect(Unit) {
- delay(2000)
- showContent = true
- }
- }
- item {
- var showContent by remember { mutableStateOf(false) }
- CardWithOverlaidPlaceholder(
- contentReady = { showContent },
- content = if (showContent) {
- {
- Text("Some content")
- Text("Some more content")
- }
- } else null
- )
- LaunchedEffect(Unit) {
- delay(2000)
- showContent = true
+ )
}
}
}
diff --git a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt
index 6c5270e..58777cc 100644
--- a/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt
+++ b/wear/compose/integration-tests/demos/src/main/java/androidx/wear/compose/integration/demos/SwipeToRevealDemo.kt
@@ -16,57 +16,39 @@
package androidx.wear.compose.integration.demos
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Email
-import androidx.compose.material.icons.outlined.Delete
-import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.Shape
-import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.ExpandableState
import androidx.wear.compose.foundation.ExperimentalWearFoundationApi
-import androidx.wear.compose.foundation.RevealScope
-import androidx.wear.compose.foundation.RevealState
import androidx.wear.compose.foundation.RevealValue
-import androidx.wear.compose.foundation.SwipeToReveal
import androidx.wear.compose.foundation.createAnchors
import androidx.wear.compose.foundation.expandableItem
-import androidx.wear.compose.foundation.fractionalPositionalThreshold
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.rememberExpandableState
import androidx.wear.compose.foundation.rememberRevealState
import androidx.wear.compose.material.AppCard
import androidx.wear.compose.material.Chip
import androidx.wear.compose.material.ChipDefaults
+import androidx.wear.compose.material.ExperimentalWearMaterialApi
import androidx.wear.compose.material.Icon
-import androidx.wear.compose.material.MaterialTheme
+import androidx.wear.compose.material.SwipeToRevealCard
+import androidx.wear.compose.material.SwipeToRevealChip
+import androidx.wear.compose.material.SwipeToRevealDefaults
import androidx.wear.compose.material.Text
-import kotlin.math.abs
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
@Composable
fun SwipeToRevealChips() {
@@ -139,12 +121,15 @@
SwipeToRevealSingleAction()
}
+/**
+ * Swipe to reveal in RTL. This is should be identical to LTR.
+ */
@Composable
fun SwipeToRevealInRtl() {
SwipeToRevealSingleAction(LayoutDirection.Rtl)
}
-@OptIn(ExperimentalWearFoundationApi::class)
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
@Composable
private fun SwipeToRevealChipExpandable(
expandableState: ExpandableState
@@ -156,34 +141,37 @@
expandableState.expanded = false
}
}
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier.size(width = 200.dp, height = 52.dp)
+ SwipeToRevealChip(
+ revealState = state,
+ action = SwipeToRevealDefaults.action(
+ icon = { Icon(SwipeToRevealDefaults.Delete, contentDescription = "Delete") },
+ label = { Text(text = "Delete") },
+ ),
+ additionalAction = SwipeToRevealDefaults.additionalAction(
+ icon = { Icon(SwipeToRevealDefaults.MoreOptions, contentDescription = "More Options") },
+ ),
+ undoAction = SwipeToRevealDefaults.undoAction(
+ label = { Text(text = "Undo") },
+ ),
) {
- SwipeToRevealWithDefaultButtons(
- shape = CircleShape,
- state = state,
- ) {
- Chip(
- onClick = { /*TODO*/ },
- colors = ChipDefaults.secondaryChipColors(),
- modifier = Modifier.fillMaxWidth(),
- label = {
- Text("S2R Chip with defaults")
- }
- )
- }
+ Chip(
+ onClick = { /*TODO*/ },
+ colors = ChipDefaults.secondaryChipColors(),
+ modifier = Modifier.fillMaxWidth(),
+ label = {
+ Text("S2R Chip with defaults")
+ }
+ )
}
}
-@OptIn(ExperimentalWearFoundationApi::class)
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
@Composable
private fun SwipeToRevealCardExpandable(
expandableState: ExpandableState,
from: String,
email: String
) {
-
val state = rememberRevealState()
LaunchedEffect(state.currentValue) {
if (state.currentValue == RevealValue.Revealed) {
@@ -191,13 +179,22 @@
expandableState.expanded = false
}
}
- SwipeToRevealWithDefaultButtons(
- shape = RoundedCornerShape(30.dp),
- state = state
+ SwipeToRevealCard(
+ revealState = state,
+ action = SwipeToRevealDefaults.action(
+ icon = { Icon(SwipeToRevealDefaults.Delete, contentDescription = "Delete") },
+ label = { Text(text = "Delete") },
+ ),
+ additionalAction = SwipeToRevealDefaults.additionalAction(
+ icon = { Icon(SwipeToRevealDefaults.MoreOptions, contentDescription = "More Options") },
+ ),
+ undoAction = SwipeToRevealDefaults.undoAction(
+ label = { Text(text = "Undo") },
+ ),
) {
AppCard(
onClick = {},
- modifier = Modifier.size(width = 200.dp, height = 100.dp),
+ modifier = Modifier.width(width = 200.dp),
appName = { Text("Gmail") },
appImage = {
Icon(
@@ -206,7 +203,7 @@
)
},
time = { Text("now") },
- title = { Text("From: $from") }
+ title = { Text("From: $from", maxLines = 1, overflow = TextOverflow.Ellipsis) }
) {
Text(
text = email,
@@ -217,52 +214,7 @@
}
}
-@OptIn(ExperimentalWearFoundationApi::class)
-@Composable
-private fun SwipeToRevealWithDefaultButtons(
- state: RevealState = rememberRevealState(),
- shape: Shape = CircleShape,
- content: @Composable () -> Unit
-) {
- val coroutineScope = rememberCoroutineScope()
- SwipeToReveal(
- action = {
- SwipeToRevealAction(
- color = MaterialTheme.colors.error,
- icon = Icons.Outlined.Delete,
- text = "Clear",
- contentDescription = "Delete",
- onClick = { state.animateTo(RevealValue.Revealed) },
- shape = shape,
- coroutineScope = coroutineScope,
- state = state
- )
- },
- additionalAction = {
- SwipeToRevealAction(
- color = MaterialTheme.colors.onSurfaceVariant,
- icon = Icons.Outlined.MoreVert,
- onClick = { state.animateTo(RevealValue.Covered) },
- shape = shape,
- coroutineScope = coroutineScope,
- state = state
- )
- },
- undoAction = {
- Chip(
- modifier = Modifier.fillMaxWidth(),
- onClick = { coroutineScope.launch { state.animateTo(RevealValue.Covered) } },
- colors = ChipDefaults.secondaryChipColors(),
- border = ChipDefaults.outlinedChipBorder(),
- label = { Text(text = "Undo") }
- )
- },
- state = state,
- content = content,
- )
-}
-
-@OptIn(ExperimentalWearFoundationApi::class)
+@OptIn(ExperimentalWearFoundationApi::class, ExperimentalWearMaterialApi::class)
@Composable
private fun SwipeToRevealSingleAction(
layoutDirection: LayoutDirection = LayoutDirection.Ltr
@@ -281,26 +233,24 @@
state = expandableState[curr]
) { expanded ->
val state = rememberRevealState(
- anchors = createAnchors(revealingAnchor = 0.5f),
- positionalThreshold = fractionalPositionalThreshold(0.5f)
+ // Setting anchor to 0.4 since there is only one action.
+ anchors = createAnchors(revealingAnchor = 0.4f),
)
if (expanded) {
CompositionLocalProvider(
LocalLayoutDirection provides layoutDirection
) {
- SwipeToReveal(
- action = {
- SwipeToRevealAction(
- color = MaterialTheme.colors.error,
- icon = Icons.Outlined.Delete,
- text = "Clear",
- contentDescription = "Delete",
- onClick = { state.animateTo(RevealValue.Revealed) },
- shape = CircleShape,
- state = state
- )
- },
- state = state
+ SwipeToRevealChip(
+ revealState = state,
+ action = SwipeToRevealDefaults.action(
+ icon = {
+ Icon(
+ SwipeToRevealDefaults.Delete,
+ contentDescription = "Delete"
+ )
+ },
+ label = { Text(text = "Delete") },
+ ),
) {
Chip(
onClick = { /*TODO*/ },
@@ -323,33 +273,3 @@
}
}
}
-
-@OptIn(ExperimentalWearFoundationApi::class)
-@Composable
-private fun RevealScope.SwipeToRevealAction(
- color: Color,
- icon: ImageVector,
- text: String? = null,
- contentDescription: String? = null,
- onClick: suspend () -> Unit = {},
- shape: Shape = RoundedCornerShape(15.dp),
- state: RevealState = rememberRevealState(),
- coroutineScope: CoroutineScope = rememberCoroutineScope(),
-) {
- Row(
- modifier = Modifier
- .clickable {
- coroutineScope.launch { onClick() }
- }
- .background(color, shape)
- .fillMaxSize(),
- horizontalArrangement = Arrangement.Center,
- verticalAlignment = Alignment.CenterVertically
- ) {
- Icon(imageVector = icon, contentDescription = contentDescription, tint = Color.DarkGray)
- if (abs(state.offset) > revealOffset && text != null) {
- Spacer(Modifier.size(5.dp))
- Text(text = text)
- }
- }
-}
diff --git a/wear/protolayout/protolayout-renderer/build.gradle b/wear/protolayout/protolayout-renderer/build.gradle
index a29d50f..b483e2a 100644
--- a/wear/protolayout/protolayout-renderer/build.gradle
+++ b/wear/protolayout/protolayout-renderer/build.gradle
@@ -33,7 +33,7 @@
api(project(":wear:protolayout:protolayout-expression-pipeline"))
implementation "androidx.concurrent:concurrent-futures:1.1.0"
implementation("androidx.core:core:1.7.0")
- implementation("androidx.wear:wear:1.3.0-rc01")
+ implementation("androidx.wear:wear:1.3.0")
testImplementation(libs.mockitoCore4)
testImplementation(libs.testExtJunit)
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java
index c96a0bc..b9696c8 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/manager/UpdateSchedulerTest.java
@@ -292,6 +292,7 @@
expect.that(mFired).isEmpty();
}
+ @SuppressWarnings("deprecation") // ScheduledAlarm usage, see b/284981234
private void advanceToTime(Long targetTime) {
while (mShadowAlarmManager.peekNextScheduledAlarm() != null
&& mShadowAlarmManager.peekNextScheduledAlarm().triggerAtTime <= targetTime) {
diff --git a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java
index cd97c3c..ba44a1f 100644
--- a/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java
+++ b/wear/tiles/tiles-renderer/src/test/java/androidx/wear/tiles/timeline/TilesTimelineManagerTest.java
@@ -365,6 +365,7 @@
.build();
}
+ @SuppressWarnings("deprecation") // ScheduledAlarm usage, see b/284981234
private void seekToTime(long timeMillis) {
ShadowAlarmManager shadowAlarmManager = shadowOf(mAlarmManager);
diff --git a/wear/watchface/watchface-complications-data-source-samples/build.gradle b/wear/watchface/watchface-complications-data-source-samples/build.gradle
index 5bc5294..bccb6ae 100644
--- a/wear/watchface/watchface-complications-data-source-samples/build.gradle
+++ b/wear/watchface/watchface-complications-data-source-samples/build.gradle
@@ -17,6 +17,7 @@
plugins {
id("AndroidXPlugin")
id("com.android.application")
+ id("kotlin-android")
}
dependencies {
diff --git a/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/WatchFaceServiceAndroidTest.kt b/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/WatchFaceServiceAndroidTest.kt
index 8c7e17e..e76aa06 100644
--- a/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/WatchFaceServiceAndroidTest.kt
+++ b/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/WatchFaceServiceAndroidTest.kt
@@ -43,9 +43,8 @@
val context: Context = ApplicationProvider.getApplicationContext()
val serviceSpy =
object : SimpleWatchFaceTestService() {
- override val resourcesContext: Context
- get() =
- this.createPackageContext(context.packageName, Context.CONTEXT_RESTRICTED)
+ override fun getResourcesContext(runtimePackage: String): Context =
+ this.createPackageContext(context.packageName, Context.CONTEXT_RESTRICTED)
}
val engine = serviceSpy.onCreateEngine() as WatchFaceService.EngineWrapper
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index c32fa26..476da70 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -437,9 +437,9 @@
}
}
- /** The context used to resolve resources. Unlocks future work. */
- protected open val resourcesContext: Context
- @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) get() = this
+ /** Returns the context used to resolve resources. */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ protected open fun getResourcesContext(runtimePackage: String): Context = this
/**
* Returns the id of the XmlSchemaAndComplicationSlotsDefinition XML resource or 0 if it can't
@@ -2644,7 +2644,7 @@
for (styleSetting in schema.userStyleSettings) {
estimatedBytes +=
styleSetting.estimateWireSizeInBytesAndValidateIconDimensions(
- resourcesContext,
+ getResourcesContext(getComponentName().packageName),
MAX_REASONABLE_SCHEMA_ICON_WIDTH,
MAX_REASONABLE_SCHEMA_ICON_HEIGHT,
)
diff --git a/window/window-core/api/1.2.0-beta02.txt b/window/window-core/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..624b2df
--- /dev/null
+++ b/window/window-core/api/1.2.0-beta02.txt
@@ -0,0 +1,38 @@
+// Signature format: 4.0
+package androidx.window.core.layout {
+
+ public final class WindowHeightSizeClass {
+ field public static final androidx.window.core.layout.WindowHeightSizeClass COMPACT;
+ field public static final androidx.window.core.layout.WindowHeightSizeClass.Companion Companion;
+ field public static final androidx.window.core.layout.WindowHeightSizeClass EXPANDED;
+ field public static final androidx.window.core.layout.WindowHeightSizeClass MEDIUM;
+ }
+
+ public static final class WindowHeightSizeClass.Companion {
+ }
+
+ public final class WindowSizeClass {
+ method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+ method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
+ method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
+ property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
+ property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
+ field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
+ }
+
+ public static final class WindowSizeClass.Companion {
+ method public androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+ }
+
+ public final class WindowWidthSizeClass {
+ field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
+ field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
+ field public static final androidx.window.core.layout.WindowWidthSizeClass EXPANDED;
+ field public static final androidx.window.core.layout.WindowWidthSizeClass MEDIUM;
+ }
+
+ public static final class WindowWidthSizeClass.Companion {
+ }
+
+}
+
diff --git a/window/window-core/api/res-1.2.0-beta02.txt b/window/window-core/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-core/api/res-1.2.0-beta02.txt
diff --git a/window/window-core/api/restricted_1.2.0-beta02.txt b/window/window-core/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..624b2df
--- /dev/null
+++ b/window/window-core/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,38 @@
+// Signature format: 4.0
+package androidx.window.core.layout {
+
+ public final class WindowHeightSizeClass {
+ field public static final androidx.window.core.layout.WindowHeightSizeClass COMPACT;
+ field public static final androidx.window.core.layout.WindowHeightSizeClass.Companion Companion;
+ field public static final androidx.window.core.layout.WindowHeightSizeClass EXPANDED;
+ field public static final androidx.window.core.layout.WindowHeightSizeClass MEDIUM;
+ }
+
+ public static final class WindowHeightSizeClass.Companion {
+ }
+
+ public final class WindowSizeClass {
+ method public static androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+ method public androidx.window.core.layout.WindowHeightSizeClass getWindowHeightSizeClass();
+ method public androidx.window.core.layout.WindowWidthSizeClass getWindowWidthSizeClass();
+ property public final androidx.window.core.layout.WindowHeightSizeClass windowHeightSizeClass;
+ property public final androidx.window.core.layout.WindowWidthSizeClass windowWidthSizeClass;
+ field public static final androidx.window.core.layout.WindowSizeClass.Companion Companion;
+ }
+
+ public static final class WindowSizeClass.Companion {
+ method public androidx.window.core.layout.WindowSizeClass compute(float dpWidth, float dpHeight);
+ }
+
+ public final class WindowWidthSizeClass {
+ field public static final androidx.window.core.layout.WindowWidthSizeClass COMPACT;
+ field public static final androidx.window.core.layout.WindowWidthSizeClass.Companion Companion;
+ field public static final androidx.window.core.layout.WindowWidthSizeClass EXPANDED;
+ field public static final androidx.window.core.layout.WindowWidthSizeClass MEDIUM;
+ }
+
+ public static final class WindowWidthSizeClass.Companion {
+ }
+
+}
+
diff --git a/window/window-java/api/1.2.0-beta02.txt b/window/window-java/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..2e19128
--- /dev/null
+++ b/window/window-java/api/1.2.0-beta02.txt
@@ -0,0 +1,32 @@
+// Signature format: 4.0
+package androidx.window.java.area {
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class WindowAreaControllerCallbackAdapter implements androidx.window.area.WindowAreaController {
+ ctor public WindowAreaControllerCallbackAdapter(androidx.window.area.WindowAreaController controller);
+ method public void addWindowAreaInfoListListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+ method public void removeWindowAreaInfoListListener(androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+ }
+
+}
+
+package androidx.window.java.embedding {
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class SplitControllerCallbackAdapter {
+ ctor public SplitControllerCallbackAdapter(androidx.window.embedding.SplitController controller);
+ method public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ method public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ }
+
+}
+
+package androidx.window.java.layout {
+
+ public final class WindowInfoTrackerCallbackAdapter implements androidx.window.layout.WindowInfoTracker {
+ ctor public WindowInfoTrackerCallbackAdapter(androidx.window.layout.WindowInfoTracker tracker);
+ method public void addWindowLayoutInfoListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ method public void addWindowLayoutInfoListener(@UiContext android.content.Context context, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ }
+
+}
+
diff --git a/window/window-java/api/res-1.2.0-beta02.txt b/window/window-java/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-java/api/res-1.2.0-beta02.txt
diff --git a/window/window-java/api/restricted_1.2.0-beta02.txt b/window/window-java/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..2e19128
--- /dev/null
+++ b/window/window-java/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,32 @@
+// Signature format: 4.0
+package androidx.window.java.area {
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class WindowAreaControllerCallbackAdapter implements androidx.window.area.WindowAreaController {
+ ctor public WindowAreaControllerCallbackAdapter(androidx.window.area.WindowAreaController controller);
+ method public void addWindowAreaInfoListListener(java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+ method public void removeWindowAreaInfoListListener(androidx.core.util.Consumer<java.util.List<androidx.window.area.WindowAreaInfo>> listener);
+ }
+
+}
+
+package androidx.window.java.embedding {
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class SplitControllerCallbackAdapter {
+ ctor public SplitControllerCallbackAdapter(androidx.window.embedding.SplitController controller);
+ method public void addSplitListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ method public void removeSplitListener(androidx.core.util.Consumer<java.util.List<androidx.window.embedding.SplitInfo>> consumer);
+ }
+
+}
+
+package androidx.window.java.layout {
+
+ public final class WindowInfoTrackerCallbackAdapter implements androidx.window.layout.WindowInfoTracker {
+ ctor public WindowInfoTrackerCallbackAdapter(androidx.window.layout.WindowInfoTracker tracker);
+ method public void addWindowLayoutInfoListener(android.app.Activity activity, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ method public void addWindowLayoutInfoListener(@UiContext android.content.Context context, java.util.concurrent.Executor executor, androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ method public void removeWindowLayoutInfoListener(androidx.core.util.Consumer<androidx.window.layout.WindowLayoutInfo> consumer);
+ }
+
+}
+
diff --git a/window/window-rxjava2/api/1.2.0-beta02.txt b/window/window-rxjava2/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..5250696
--- /dev/null
+++ b/window/window-rxjava2/api/1.2.0-beta02.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+ public final class WindowInfoTrackerRx {
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ }
+
+}
+
diff --git a/window/window-rxjava2/api/res-1.2.0-beta02.txt b/window/window-rxjava2/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-rxjava2/api/res-1.2.0-beta02.txt
diff --git a/window/window-rxjava2/api/restricted_1.2.0-beta02.txt b/window/window-rxjava2/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..5250696
--- /dev/null
+++ b/window/window-rxjava2/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava2.layout {
+
+ public final class WindowInfoTrackerRx {
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ }
+
+}
+
diff --git a/window/window-rxjava3/api/1.2.0-beta02.txt b/window/window-rxjava3/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..23510cc
--- /dev/null
+++ b/window/window-rxjava3/api/1.2.0-beta02.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+ public final class WindowInfoTrackerRx {
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ }
+
+}
+
diff --git a/window/window-rxjava3/api/res-1.2.0-beta02.txt b/window/window-rxjava3/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-rxjava3/api/res-1.2.0-beta02.txt
diff --git a/window/window-rxjava3/api/restricted_1.2.0-beta02.txt b/window/window-rxjava3/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..23510cc
--- /dev/null
+++ b/window/window-rxjava3/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,12 @@
+// Signature format: 4.0
+package androidx.window.rxjava3.layout {
+
+ public final class WindowInfoTrackerRx {
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.rxjava3.core.Flowable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoFlowable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, android.app.Activity activity);
+ method public static io.reactivex.rxjava3.core.Observable<androidx.window.layout.WindowLayoutInfo> windowLayoutInfoObservable(androidx.window.layout.WindowInfoTracker, @UiContext android.content.Context context);
+ }
+
+}
+
diff --git a/window/window-testing/api/1.2.0-beta02.txt b/window/window-testing/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..847a9e8
--- /dev/null
+++ b/window/window-testing/api/1.2.0-beta02.txt
@@ -0,0 +1,73 @@
+// Signature format: 4.0
+package androidx.window.testing.embedding {
+
+ public final class ActivityEmbeddingRule implements org.junit.rules.TestRule {
+ ctor public ActivityEmbeddingRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideIsActivityEmbedded(android.app.Activity activity, boolean isActivityEmbedded);
+ method public void overrideSplitInfo(android.app.Activity activity, java.util.List<androidx.window.embedding.SplitInfo> splitInfoList);
+ method public void overrideSplitSupportStatus(androidx.window.embedding.SplitController.SplitSupportStatus status);
+ }
+
+ public final class TestActivityStack {
+ method public static androidx.window.embedding.ActivityStack createTestActivityStack();
+ method public static androidx.window.embedding.ActivityStack createTestActivityStack(optional java.util.List<? extends android.app.Activity> activitiesInProcess);
+ method public static androidx.window.embedding.ActivityStack createTestActivityStack(optional java.util.List<? extends android.app.Activity> activitiesInProcess, optional boolean isEmpty);
+ }
+
+ public final class TestSplitAttributesCalculatorParams {
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes, optional boolean areDefaultConstraintsSatisfied);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes, optional boolean areDefaultConstraintsSatisfied, optional String? splitRuleTag);
+ }
+
+ public final class TestSplitInfo {
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo();
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack);
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack, optional androidx.window.embedding.ActivityStack secondActivityStack);
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack, optional androidx.window.embedding.ActivityStack secondActivityStack, optional androidx.window.embedding.SplitAttributes splitAttributes);
+ }
+
+}
+
+package androidx.window.testing.layout {
+
+ public final class DisplayFeatureTesting {
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center, optional int size);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center, optional int size);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+ }
+
+ public final class FoldingFeatureTestingConstants {
+ field public static final int FOLDING_FEATURE_CENTER_DEFAULT = -1; // 0xffffffff
+ field public static final androidx.window.testing.layout.FoldingFeatureTestingConstants INSTANCE;
+ }
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+ }
+
+ public final class WindowLayoutInfoTesting {
+ method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo();
+ method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo(optional java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+ }
+
+ public final class WindowMetricsCalculatorRule implements org.junit.rules.TestRule {
+ ctor public WindowMetricsCalculatorRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ }
+
+}
+
diff --git a/window/window-testing/api/res-1.2.0-beta02.txt b/window/window-testing/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/window/window-testing/api/res-1.2.0-beta02.txt
diff --git a/window/window-testing/api/restricted_1.2.0-beta02.txt b/window/window-testing/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..847a9e8
--- /dev/null
+++ b/window/window-testing/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,73 @@
+// Signature format: 4.0
+package androidx.window.testing.embedding {
+
+ public final class ActivityEmbeddingRule implements org.junit.rules.TestRule {
+ ctor public ActivityEmbeddingRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideIsActivityEmbedded(android.app.Activity activity, boolean isActivityEmbedded);
+ method public void overrideSplitInfo(android.app.Activity activity, java.util.List<androidx.window.embedding.SplitInfo> splitInfoList);
+ method public void overrideSplitSupportStatus(androidx.window.embedding.SplitController.SplitSupportStatus status);
+ }
+
+ public final class TestActivityStack {
+ method public static androidx.window.embedding.ActivityStack createTestActivityStack();
+ method public static androidx.window.embedding.ActivityStack createTestActivityStack(optional java.util.List<? extends android.app.Activity> activitiesInProcess);
+ method public static androidx.window.embedding.ActivityStack createTestActivityStack(optional java.util.List<? extends android.app.Activity> activitiesInProcess, optional boolean isEmpty);
+ }
+
+ public final class TestSplitAttributesCalculatorParams {
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes, optional boolean areDefaultConstraintsSatisfied);
+ method public static androidx.window.embedding.SplitAttributesCalculatorParams createTestSplitAttributesCalculatorParams(androidx.window.layout.WindowMetrics parentWindowMetrics, optional android.content.res.Configuration parentConfiguration, optional androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo, optional androidx.window.embedding.SplitAttributes defaultSplitAttributes, optional boolean areDefaultConstraintsSatisfied, optional String? splitRuleTag);
+ }
+
+ public final class TestSplitInfo {
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo();
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack);
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack, optional androidx.window.embedding.ActivityStack secondActivityStack);
+ method public static androidx.window.embedding.SplitInfo createTestSplitInfo(optional androidx.window.embedding.ActivityStack primaryActivityStack, optional androidx.window.embedding.ActivityStack secondActivityStack, optional androidx.window.embedding.SplitAttributes splitAttributes);
+ }
+
+}
+
+package androidx.window.testing.layout {
+
+ public final class DisplayFeatureTesting {
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center, optional int size);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.app.Activity activity, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center, optional int size);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state);
+ method public static androidx.window.layout.FoldingFeature createFoldingFeature(android.graphics.Rect windowBounds, optional @IntRange(from=-1L) int center, optional int size, optional androidx.window.layout.FoldingFeature.State state, optional androidx.window.layout.FoldingFeature.Orientation orientation);
+ }
+
+ public final class FoldingFeatureTestingConstants {
+ field public static final int FOLDING_FEATURE_CENTER_DEFAULT = -1; // 0xffffffff
+ field public static final androidx.window.testing.layout.FoldingFeatureTestingConstants INSTANCE;
+ }
+
+ public final class WindowLayoutInfoPublisherRule implements org.junit.rules.TestRule {
+ ctor public WindowLayoutInfoPublisherRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ method public void overrideWindowLayoutInfo(androidx.window.layout.WindowLayoutInfo info);
+ }
+
+ public final class WindowLayoutInfoTesting {
+ method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo();
+ method public static androidx.window.layout.WindowLayoutInfo createWindowLayoutInfo(optional java.util.List<? extends androidx.window.layout.DisplayFeature> displayFeatures);
+ }
+
+ public final class WindowMetricsCalculatorRule implements org.junit.rules.TestRule {
+ ctor public WindowMetricsCalculatorRule();
+ method public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description);
+ }
+
+}
+
diff --git a/window/window/api/1.2.0-beta02.txt b/window/window/api/1.2.0-beta02.txt
new file mode 100644
index 0000000..7c79bde
--- /dev/null
+++ b/window/window/api/1.2.0-beta02.txt
@@ -0,0 +1,465 @@
+// Signature format: 4.0
+package androidx.window {
+
+ public final class WindowProperties {
+ field public static final androidx.window.WindowProperties INSTANCE;
+ field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
+ field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
+ field public static final String PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED = "android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED";
+ field public static final String PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE";
+ field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
+ }
+
+}
+
+package androidx.window.area {
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class WindowAreaCapability {
+ method public androidx.window.area.WindowAreaCapability.Operation getOperation();
+ method public androidx.window.area.WindowAreaCapability.Status getStatus();
+ property public final androidx.window.area.WindowAreaCapability.Operation operation;
+ property public final androidx.window.area.WindowAreaCapability.Status status;
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static final class WindowAreaCapability.Operation {
+ field public static final androidx.window.area.WindowAreaCapability.Operation.Companion Companion;
+ field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_PRESENT_ON_AREA;
+ field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_TRANSFER_ACTIVITY_TO_AREA;
+ }
+
+ public static final class WindowAreaCapability.Operation.Companion {
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static final class WindowAreaCapability.Status {
+ field public static final androidx.window.area.WindowAreaCapability.Status.Companion Companion;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_ACTIVE;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_AVAILABLE;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNAVAILABLE;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNSUPPORTED;
+ }
+
+ public static final class WindowAreaCapability.Status.Companion {
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaController {
+ method public static androidx.window.area.WindowAreaController getOrCreate();
+ method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> getWindowAreaInfos();
+ method public void presentContentOnWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaPresentationSessionCallback windowAreaPresentationSessionCallback);
+ method public void transferActivityToWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaSessionCallback windowAreaSessionCallback);
+ property public abstract kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> windowAreaInfos;
+ field public static final androidx.window.area.WindowAreaController.Companion Companion;
+ }
+
+ public static final class WindowAreaController.Companion {
+ method public androidx.window.area.WindowAreaController getOrCreate();
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class WindowAreaInfo {
+ method public androidx.window.area.WindowAreaSession? getActiveSession(androidx.window.area.WindowAreaCapability.Operation operation);
+ method public androidx.window.area.WindowAreaCapability? getCapability(androidx.window.area.WindowAreaCapability.Operation operation);
+ method public androidx.window.layout.WindowMetrics getMetrics();
+ method public android.os.Binder getToken();
+ method public androidx.window.area.WindowAreaInfo.Type getType();
+ method public void setMetrics(androidx.window.layout.WindowMetrics);
+ property public final androidx.window.layout.WindowMetrics metrics;
+ property public final android.os.Binder token;
+ property public final androidx.window.area.WindowAreaInfo.Type type;
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static final class WindowAreaInfo.Type {
+ field public static final androidx.window.area.WindowAreaInfo.Type.Companion Companion;
+ field public static final androidx.window.area.WindowAreaInfo.Type TYPE_REAR_FACING;
+ }
+
+ public static final class WindowAreaInfo.Type.Companion {
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaPresentationSessionCallback {
+ method public void onContainerVisibilityChanged(boolean isVisible);
+ method public void onSessionEnded(Throwable? t);
+ method public void onSessionStarted(androidx.window.area.WindowAreaSessionPresenter session);
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSession {
+ method public void close();
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSessionCallback {
+ method public void onSessionEnded(Throwable? t);
+ method public void onSessionStarted(androidx.window.area.WindowAreaSession session);
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSessionPresenter extends androidx.window.area.WindowAreaSession {
+ method public android.content.Context getContext();
+ method public void setContentView(android.view.View view);
+ property public abstract android.content.Context context;
+ }
+
+}
+
+package androidx.window.core {
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalWindowApi {
+ }
+
+}
+
+package androidx.window.embedding {
+
+ public final class ActivityEmbeddingController {
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
+ method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+ method public boolean isActivityEmbedded(android.app.Activity activity);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
+ field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
+ }
+
+ public static final class ActivityEmbeddingController.Companion {
+ method public androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+ }
+
+ public final class ActivityEmbeddingOptions {
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+ }
+
+ public final class ActivityFilter {
+ ctor public ActivityFilter(android.content.ComponentName componentName, String? intentAction);
+ method public android.content.ComponentName getComponentName();
+ method public String? getIntentAction();
+ method public boolean matchesActivity(android.app.Activity activity);
+ method public boolean matchesIntent(android.content.Intent intent);
+ property public final android.content.ComponentName componentName;
+ property public final String? intentAction;
+ }
+
+ public final class ActivityRule extends androidx.window.embedding.EmbeddingRule {
+ method public boolean getAlwaysExpand();
+ method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+ property public final boolean alwaysExpand;
+ property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+ }
+
+ public static final class ActivityRule.Builder {
+ ctor public ActivityRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters);
+ method public androidx.window.embedding.ActivityRule build();
+ method public androidx.window.embedding.ActivityRule.Builder setAlwaysExpand(boolean alwaysExpand);
+ method public androidx.window.embedding.ActivityRule.Builder setTag(String? tag);
+ }
+
+ public final class ActivityStack {
+ method public operator boolean contains(android.app.Activity activity);
+ method public boolean isEmpty();
+ property public final boolean isEmpty;
+ }
+
+ public final class EmbeddingAspectRatio {
+ method public static androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+ field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_ALLOW;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_DISALLOW;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio.Companion Companion;
+ }
+
+ public static final class EmbeddingAspectRatio.Companion {
+ method public androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+ }
+
+ public abstract class EmbeddingRule {
+ method public final String? getTag();
+ property public final String? tag;
+ }
+
+ public final class RuleController {
+ method public void addRule(androidx.window.embedding.EmbeddingRule rule);
+ method public void clearRules();
+ method public static androidx.window.embedding.RuleController getInstance(android.content.Context context);
+ method public java.util.Set<androidx.window.embedding.EmbeddingRule> getRules();
+ method public static java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+ method public void removeRule(androidx.window.embedding.EmbeddingRule rule);
+ method public void setRules(java.util.Set<? extends androidx.window.embedding.EmbeddingRule> rules);
+ field public static final androidx.window.embedding.RuleController.Companion Companion;
+ }
+
+ public static final class RuleController.Companion {
+ method public androidx.window.embedding.RuleController getInstance(android.content.Context context);
+ method public java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+ }
+
+ public final class SplitAttributes {
+ method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
+ method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
+ property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
+ property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
+ field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
+ }
+
+ public static final class SplitAttributes.Builder {
+ ctor public SplitAttributes.Builder();
+ method public androidx.window.embedding.SplitAttributes build();
+ method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
+ method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
+ }
+
+ public static final class SplitAttributes.Companion {
+ }
+
+ public static final class SplitAttributes.LayoutDirection {
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection BOTTOM_TO_TOP;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection.Companion Companion;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LEFT_TO_RIGHT;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LOCALE;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection RIGHT_TO_LEFT;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection TOP_TO_BOTTOM;
+ }
+
+ public static final class SplitAttributes.LayoutDirection.Companion {
+ }
+
+ public static final class SplitAttributes.SplitType {
+ method public static androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+ field public static final androidx.window.embedding.SplitAttributes.SplitType.Companion Companion;
+ field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EQUAL;
+ field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EXPAND;
+ field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_HINGE;
+ }
+
+ public static final class SplitAttributes.SplitType.Companion {
+ method public androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+ }
+
+ public final class SplitAttributesCalculatorParams {
+ method public boolean getAreDefaultConstraintsSatisfied();
+ method public androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+ method public android.content.res.Configuration getParentConfiguration();
+ method public androidx.window.layout.WindowLayoutInfo getParentWindowLayoutInfo();
+ method public androidx.window.layout.WindowMetrics getParentWindowMetrics();
+ method public String? getSplitRuleTag();
+ property public final boolean areDefaultConstraintsSatisfied;
+ property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+ property public final android.content.res.Configuration parentConfiguration;
+ property public final androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo;
+ property public final androidx.window.layout.WindowMetrics parentWindowMetrics;
+ property public final String? splitRuleTag;
+ }
+
+ public final class SplitController {
+ method public void clearSplitAttributesCalculator();
+ method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
+ method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
+ method public boolean isSplitAttributesCalculatorSupported();
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
+ method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+ method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
+ property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
+ field public static final androidx.window.embedding.SplitController.Companion Companion;
+ }
+
+ public static final class SplitController.Companion {
+ method public androidx.window.embedding.SplitController getInstance(android.content.Context context);
+ }
+
+ public static final class SplitController.SplitSupportStatus {
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus.Companion Companion;
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_AVAILABLE;
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_ERROR_PROPERTY_NOT_DECLARED;
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_UNAVAILABLE;
+ }
+
+ public static final class SplitController.SplitSupportStatus.Companion {
+ }
+
+ public final class SplitInfo {
+ method public operator boolean contains(android.app.Activity activity);
+ method public androidx.window.embedding.ActivityStack getPrimaryActivityStack();
+ method public androidx.window.embedding.ActivityStack getSecondaryActivityStack();
+ method public androidx.window.embedding.SplitAttributes getSplitAttributes();
+ property public final androidx.window.embedding.ActivityStack primaryActivityStack;
+ property public final androidx.window.embedding.ActivityStack secondaryActivityStack;
+ property public final androidx.window.embedding.SplitAttributes splitAttributes;
+ }
+
+ public final class SplitPairFilter {
+ ctor public SplitPairFilter(android.content.ComponentName primaryActivityName, android.content.ComponentName secondaryActivityName, String? secondaryActivityIntentAction);
+ method public android.content.ComponentName getPrimaryActivityName();
+ method public String? getSecondaryActivityIntentAction();
+ method public android.content.ComponentName getSecondaryActivityName();
+ method public boolean matchesActivityIntentPair(android.app.Activity primaryActivity, android.content.Intent secondaryActivityIntent);
+ method public boolean matchesActivityPair(android.app.Activity primaryActivity, android.app.Activity secondaryActivity);
+ property public final android.content.ComponentName primaryActivityName;
+ property public final String? secondaryActivityIntentAction;
+ property public final android.content.ComponentName secondaryActivityName;
+ }
+
+ public final class SplitPairRule extends androidx.window.embedding.SplitRule {
+ method public boolean getClearTop();
+ method public java.util.Set<androidx.window.embedding.SplitPairFilter> getFilters();
+ method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithSecondary();
+ method public androidx.window.embedding.SplitRule.FinishBehavior getFinishSecondaryWithPrimary();
+ property public final boolean clearTop;
+ property public final java.util.Set<androidx.window.embedding.SplitPairFilter> filters;
+ property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary;
+ property public final androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary;
+ }
+
+ public static final class SplitPairRule.Builder {
+ ctor public SplitPairRule.Builder(java.util.Set<androidx.window.embedding.SplitPairFilter> filters);
+ method public androidx.window.embedding.SplitPairRule build();
+ method public androidx.window.embedding.SplitPairRule.Builder setClearTop(boolean clearTop);
+ method public androidx.window.embedding.SplitPairRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+ method public androidx.window.embedding.SplitPairRule.Builder setFinishPrimaryWithSecondary(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary);
+ method public androidx.window.embedding.SplitPairRule.Builder setFinishSecondaryWithPrimary(androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary);
+ method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPairRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+ method public androidx.window.embedding.SplitPairRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+ method public androidx.window.embedding.SplitPairRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+ method public androidx.window.embedding.SplitPairRule.Builder setTag(String? tag);
+ }
+
+ public final class SplitPlaceholderRule extends androidx.window.embedding.SplitRule {
+ method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+ method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithPlaceholder();
+ method public android.content.Intent getPlaceholderIntent();
+ method public boolean isSticky();
+ property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+ property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder;
+ property public final boolean isSticky;
+ property public final android.content.Intent placeholderIntent;
+ }
+
+ public static final class SplitPlaceholderRule.Builder {
+ ctor public SplitPlaceholderRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters, android.content.Intent placeholderIntent);
+ method public androidx.window.embedding.SplitPlaceholderRule build();
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setFinishPrimaryWithPlaceholder(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setSticky(boolean isSticky);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setTag(String? tag);
+ }
+
+ public class SplitRule extends androidx.window.embedding.EmbeddingRule {
+ method public final androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+ method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInLandscape();
+ method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInPortrait();
+ method public final int getMinHeightDp();
+ method public final int getMinSmallestWidthDp();
+ method public final int getMinWidthDp();
+ property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+ property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInLandscape;
+ property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInPortrait;
+ property public final int minHeightDp;
+ property public final int minSmallestWidthDp;
+ property public final int minWidthDp;
+ field public static final androidx.window.embedding.SplitRule.Companion Companion;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_LANDSCAPE_DEFAULT;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT;
+ field public static final int SPLIT_MIN_DIMENSION_ALWAYS_ALLOW = 0; // 0x0
+ field public static final int SPLIT_MIN_DIMENSION_DP_DEFAULT = 600; // 0x258
+ }
+
+ public static final class SplitRule.Companion {
+ }
+
+ public static final class SplitRule.FinishBehavior {
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior ADJACENT;
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior ALWAYS;
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior.Companion Companion;
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior NEVER;
+ }
+
+ public static final class SplitRule.FinishBehavior.Companion {
+ }
+
+}
+
+package androidx.window.layout {
+
+ public interface DisplayFeature {
+ method public android.graphics.Rect getBounds();
+ property public abstract android.graphics.Rect bounds;
+ }
+
+ public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+ method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+ method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+ method public androidx.window.layout.FoldingFeature.State getState();
+ method public boolean isSeparating();
+ property public abstract boolean isSeparating;
+ property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+ property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+ property public abstract androidx.window.layout.FoldingFeature.State state;
+ }
+
+ public static final class FoldingFeature.OcclusionType {
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+ }
+
+ public static final class FoldingFeature.OcclusionType.Companion {
+ }
+
+ public static final class FoldingFeature.Orientation {
+ field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+ field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+ }
+
+ public static final class FoldingFeature.Orientation.Companion {
+ }
+
+ public static final class FoldingFeature.State {
+ field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.State FLAT;
+ field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+ }
+
+ public static final class FoldingFeature.State.Companion {
+ }
+
+ public interface WindowInfoTracker {
+ method public static androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(android.app.Activity activity);
+ method public default kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(@UiContext android.content.Context context);
+ field public static final androidx.window.layout.WindowInfoTracker.Companion Companion;
+ }
+
+ public static final class WindowInfoTracker.Companion {
+ method public androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+ }
+
+ public final class WindowLayoutInfo {
+ method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+ property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+ }
+
+ public final class WindowMetrics {
+ method public android.graphics.Rect getBounds();
+ method @SuppressCompatibility @RequiresApi(android.os.Build.VERSION_CODES.R) @androidx.window.core.ExperimentalWindowApi public androidx.core.view.WindowInsetsCompat getWindowInsets();
+ property public final android.graphics.Rect bounds;
+ }
+
+ public interface WindowMetricsCalculator {
+ method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+ method public default androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(@UiContext android.content.Context context);
+ method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+ method public default androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(@UiContext android.content.Context context);
+ method public static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+ }
+
+ public static final class WindowMetricsCalculator.Companion {
+ method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ }
+
+}
+
diff --git a/window/window/api/res-1.2.0-beta02.txt b/window/window/api/res-1.2.0-beta02.txt
new file mode 100644
index 0000000..185352b
--- /dev/null
+++ b/window/window/api/res-1.2.0-beta02.txt
@@ -0,0 +1,21 @@
+attr activityAction
+attr activityName
+attr alwaysExpand
+attr animationBackgroundColor
+attr clearTop
+attr finishPrimaryWithPlaceholder
+attr finishPrimaryWithSecondary
+attr finishSecondaryWithPrimary
+attr placeholderActivityName
+attr primaryActivityName
+attr secondaryActivityAction
+attr secondaryActivityName
+attr splitLayoutDirection
+attr splitMaxAspectRatioInLandscape
+attr splitMaxAspectRatioInPortrait
+attr splitMinHeightDp
+attr splitMinSmallestWidthDp
+attr splitMinWidthDp
+attr splitRatio
+attr stickyPlaceholder
+attr tag
diff --git a/window/window/api/restricted_1.2.0-beta02.txt b/window/window/api/restricted_1.2.0-beta02.txt
new file mode 100644
index 0000000..7c79bde
--- /dev/null
+++ b/window/window/api/restricted_1.2.0-beta02.txt
@@ -0,0 +1,465 @@
+// Signature format: 4.0
+package androidx.window {
+
+ public final class WindowProperties {
+ field public static final androidx.window.WindowProperties INSTANCE;
+ field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
+ field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
+ field public static final String PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED = "android.window.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED";
+ field public static final String PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE";
+ field public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES";
+ }
+
+}
+
+package androidx.window.area {
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class WindowAreaCapability {
+ method public androidx.window.area.WindowAreaCapability.Operation getOperation();
+ method public androidx.window.area.WindowAreaCapability.Status getStatus();
+ property public final androidx.window.area.WindowAreaCapability.Operation operation;
+ property public final androidx.window.area.WindowAreaCapability.Status status;
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static final class WindowAreaCapability.Operation {
+ field public static final androidx.window.area.WindowAreaCapability.Operation.Companion Companion;
+ field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_PRESENT_ON_AREA;
+ field public static final androidx.window.area.WindowAreaCapability.Operation OPERATION_TRANSFER_ACTIVITY_TO_AREA;
+ }
+
+ public static final class WindowAreaCapability.Operation.Companion {
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static final class WindowAreaCapability.Status {
+ field public static final androidx.window.area.WindowAreaCapability.Status.Companion Companion;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_ACTIVE;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_AVAILABLE;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNAVAILABLE;
+ field public static final androidx.window.area.WindowAreaCapability.Status WINDOW_AREA_STATUS_UNSUPPORTED;
+ }
+
+ public static final class WindowAreaCapability.Status.Companion {
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaController {
+ method public static androidx.window.area.WindowAreaController getOrCreate();
+ method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> getWindowAreaInfos();
+ method public void presentContentOnWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaPresentationSessionCallback windowAreaPresentationSessionCallback);
+ method public void transferActivityToWindowArea(android.os.Binder token, android.app.Activity activity, java.util.concurrent.Executor executor, androidx.window.area.WindowAreaSessionCallback windowAreaSessionCallback);
+ property public abstract kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.area.WindowAreaInfo>> windowAreaInfos;
+ field public static final androidx.window.area.WindowAreaController.Companion Companion;
+ }
+
+ public static final class WindowAreaController.Companion {
+ method public androidx.window.area.WindowAreaController getOrCreate();
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public final class WindowAreaInfo {
+ method public androidx.window.area.WindowAreaSession? getActiveSession(androidx.window.area.WindowAreaCapability.Operation operation);
+ method public androidx.window.area.WindowAreaCapability? getCapability(androidx.window.area.WindowAreaCapability.Operation operation);
+ method public androidx.window.layout.WindowMetrics getMetrics();
+ method public android.os.Binder getToken();
+ method public androidx.window.area.WindowAreaInfo.Type getType();
+ method public void setMetrics(androidx.window.layout.WindowMetrics);
+ property public final androidx.window.layout.WindowMetrics metrics;
+ property public final android.os.Binder token;
+ property public final androidx.window.area.WindowAreaInfo.Type type;
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static final class WindowAreaInfo.Type {
+ field public static final androidx.window.area.WindowAreaInfo.Type.Companion Companion;
+ field public static final androidx.window.area.WindowAreaInfo.Type TYPE_REAR_FACING;
+ }
+
+ public static final class WindowAreaInfo.Type.Companion {
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaPresentationSessionCallback {
+ method public void onContainerVisibilityChanged(boolean isVisible);
+ method public void onSessionEnded(Throwable? t);
+ method public void onSessionStarted(androidx.window.area.WindowAreaSessionPresenter session);
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSession {
+ method public void close();
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSessionCallback {
+ method public void onSessionEnded(Throwable? t);
+ method public void onSessionStarted(androidx.window.area.WindowAreaSession session);
+ }
+
+ @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public interface WindowAreaSessionPresenter extends androidx.window.area.WindowAreaSession {
+ method public android.content.Context getContext();
+ method public void setContentView(android.view.View view);
+ property public abstract android.content.Context context;
+ }
+
+}
+
+package androidx.window.core {
+
+ @SuppressCompatibility @kotlin.RequiresOptIn(level=kotlin.RequiresOptIn.Level.WARNING) @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalWindowApi {
+ }
+
+}
+
+package androidx.window.embedding {
+
+ public final class ActivityEmbeddingController {
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void finishActivityStacks(java.util.Set<androidx.window.embedding.ActivityStack> activityStacks);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public androidx.window.embedding.ActivityStack? getActivityStack(android.app.Activity activity);
+ method public static androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+ method public boolean isActivityEmbedded(android.app.Activity activity);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isFinishingActivityStacksSupported();
+ field public static final androidx.window.embedding.ActivityEmbeddingController.Companion Companion;
+ }
+
+ public static final class ActivityEmbeddingController.Companion {
+ method public androidx.window.embedding.ActivityEmbeddingController getInstance(android.content.Context context);
+ }
+
+ public final class ActivityEmbeddingOptions {
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static boolean isSetLaunchingActivityStackSupported(android.app.ActivityOptions);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.app.Activity activity);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public static android.app.ActivityOptions setLaunchingActivityStack(android.app.ActivityOptions, android.content.Context context, androidx.window.embedding.ActivityStack activityStack);
+ }
+
+ public final class ActivityFilter {
+ ctor public ActivityFilter(android.content.ComponentName componentName, String? intentAction);
+ method public android.content.ComponentName getComponentName();
+ method public String? getIntentAction();
+ method public boolean matchesActivity(android.app.Activity activity);
+ method public boolean matchesIntent(android.content.Intent intent);
+ property public final android.content.ComponentName componentName;
+ property public final String? intentAction;
+ }
+
+ public final class ActivityRule extends androidx.window.embedding.EmbeddingRule {
+ method public boolean getAlwaysExpand();
+ method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+ property public final boolean alwaysExpand;
+ property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+ }
+
+ public static final class ActivityRule.Builder {
+ ctor public ActivityRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters);
+ method public androidx.window.embedding.ActivityRule build();
+ method public androidx.window.embedding.ActivityRule.Builder setAlwaysExpand(boolean alwaysExpand);
+ method public androidx.window.embedding.ActivityRule.Builder setTag(String? tag);
+ }
+
+ public final class ActivityStack {
+ method public operator boolean contains(android.app.Activity activity);
+ method public boolean isEmpty();
+ property public final boolean isEmpty;
+ }
+
+ public final class EmbeddingAspectRatio {
+ method public static androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+ field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_ALLOW;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio ALWAYS_DISALLOW;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio.Companion Companion;
+ }
+
+ public static final class EmbeddingAspectRatio.Companion {
+ method public androidx.window.embedding.EmbeddingAspectRatio ratio(@FloatRange(from=1.0, fromInclusive=false) float ratio);
+ }
+
+ public abstract class EmbeddingRule {
+ method public final String? getTag();
+ property public final String? tag;
+ }
+
+ public final class RuleController {
+ method public void addRule(androidx.window.embedding.EmbeddingRule rule);
+ method public void clearRules();
+ method public static androidx.window.embedding.RuleController getInstance(android.content.Context context);
+ method public java.util.Set<androidx.window.embedding.EmbeddingRule> getRules();
+ method public static java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+ method public void removeRule(androidx.window.embedding.EmbeddingRule rule);
+ method public void setRules(java.util.Set<? extends androidx.window.embedding.EmbeddingRule> rules);
+ field public static final androidx.window.embedding.RuleController.Companion Companion;
+ }
+
+ public static final class RuleController.Companion {
+ method public androidx.window.embedding.RuleController getInstance(android.content.Context context);
+ method public java.util.Set<androidx.window.embedding.EmbeddingRule> parseRules(android.content.Context context, @XmlRes int staticRuleResourceId);
+ }
+
+ public final class SplitAttributes {
+ method public androidx.window.embedding.SplitAttributes.LayoutDirection getLayoutDirection();
+ method public androidx.window.embedding.SplitAttributes.SplitType getSplitType();
+ property public final androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection;
+ property public final androidx.window.embedding.SplitAttributes.SplitType splitType;
+ field public static final androidx.window.embedding.SplitAttributes.Companion Companion;
+ }
+
+ public static final class SplitAttributes.Builder {
+ ctor public SplitAttributes.Builder();
+ method public androidx.window.embedding.SplitAttributes build();
+ method public androidx.window.embedding.SplitAttributes.Builder setLayoutDirection(androidx.window.embedding.SplitAttributes.LayoutDirection layoutDirection);
+ method public androidx.window.embedding.SplitAttributes.Builder setSplitType(androidx.window.embedding.SplitAttributes.SplitType type);
+ }
+
+ public static final class SplitAttributes.Companion {
+ }
+
+ public static final class SplitAttributes.LayoutDirection {
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection BOTTOM_TO_TOP;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection.Companion Companion;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LEFT_TO_RIGHT;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection LOCALE;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection RIGHT_TO_LEFT;
+ field public static final androidx.window.embedding.SplitAttributes.LayoutDirection TOP_TO_BOTTOM;
+ }
+
+ public static final class SplitAttributes.LayoutDirection.Companion {
+ }
+
+ public static final class SplitAttributes.SplitType {
+ method public static androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+ field public static final androidx.window.embedding.SplitAttributes.SplitType.Companion Companion;
+ field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EQUAL;
+ field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_EXPAND;
+ field public static final androidx.window.embedding.SplitAttributes.SplitType SPLIT_TYPE_HINGE;
+ }
+
+ public static final class SplitAttributes.SplitType.Companion {
+ method public androidx.window.embedding.SplitAttributes.SplitType ratio(@FloatRange(from=0.0, to=1.0, fromInclusive=false, toInclusive=false) float ratio);
+ }
+
+ public final class SplitAttributesCalculatorParams {
+ method public boolean getAreDefaultConstraintsSatisfied();
+ method public androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+ method public android.content.res.Configuration getParentConfiguration();
+ method public androidx.window.layout.WindowLayoutInfo getParentWindowLayoutInfo();
+ method public androidx.window.layout.WindowMetrics getParentWindowMetrics();
+ method public String? getSplitRuleTag();
+ property public final boolean areDefaultConstraintsSatisfied;
+ property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+ property public final android.content.res.Configuration parentConfiguration;
+ property public final androidx.window.layout.WindowLayoutInfo parentWindowLayoutInfo;
+ property public final androidx.window.layout.WindowMetrics parentWindowMetrics;
+ property public final String? splitRuleTag;
+ }
+
+ public final class SplitController {
+ method public void clearSplitAttributesCalculator();
+ method public static androidx.window.embedding.SplitController getInstance(android.content.Context context);
+ method public androidx.window.embedding.SplitController.SplitSupportStatus getSplitSupportStatus();
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void invalidateTopVisibleSplitAttributes();
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isInvalidatingTopVisibleSplitAttributesSupported();
+ method public boolean isSplitAttributesCalculatorSupported();
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public boolean isUpdatingSplitAttributesSupported();
+ method public void setSplitAttributesCalculator(kotlin.jvm.functions.Function1<? super androidx.window.embedding.SplitAttributesCalculatorParams,androidx.window.embedding.SplitAttributes> calculator);
+ method public kotlinx.coroutines.flow.Flow<java.util.List<androidx.window.embedding.SplitInfo>> splitInfoList(android.app.Activity activity);
+ method @SuppressCompatibility @androidx.window.core.ExperimentalWindowApi public void updateSplitAttributes(androidx.window.embedding.SplitInfo splitInfo, androidx.window.embedding.SplitAttributes splitAttributes);
+ property public final androidx.window.embedding.SplitController.SplitSupportStatus splitSupportStatus;
+ field public static final androidx.window.embedding.SplitController.Companion Companion;
+ }
+
+ public static final class SplitController.Companion {
+ method public androidx.window.embedding.SplitController getInstance(android.content.Context context);
+ }
+
+ public static final class SplitController.SplitSupportStatus {
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus.Companion Companion;
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_AVAILABLE;
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_ERROR_PROPERTY_NOT_DECLARED;
+ field public static final androidx.window.embedding.SplitController.SplitSupportStatus SPLIT_UNAVAILABLE;
+ }
+
+ public static final class SplitController.SplitSupportStatus.Companion {
+ }
+
+ public final class SplitInfo {
+ method public operator boolean contains(android.app.Activity activity);
+ method public androidx.window.embedding.ActivityStack getPrimaryActivityStack();
+ method public androidx.window.embedding.ActivityStack getSecondaryActivityStack();
+ method public androidx.window.embedding.SplitAttributes getSplitAttributes();
+ property public final androidx.window.embedding.ActivityStack primaryActivityStack;
+ property public final androidx.window.embedding.ActivityStack secondaryActivityStack;
+ property public final androidx.window.embedding.SplitAttributes splitAttributes;
+ }
+
+ public final class SplitPairFilter {
+ ctor public SplitPairFilter(android.content.ComponentName primaryActivityName, android.content.ComponentName secondaryActivityName, String? secondaryActivityIntentAction);
+ method public android.content.ComponentName getPrimaryActivityName();
+ method public String? getSecondaryActivityIntentAction();
+ method public android.content.ComponentName getSecondaryActivityName();
+ method public boolean matchesActivityIntentPair(android.app.Activity primaryActivity, android.content.Intent secondaryActivityIntent);
+ method public boolean matchesActivityPair(android.app.Activity primaryActivity, android.app.Activity secondaryActivity);
+ property public final android.content.ComponentName primaryActivityName;
+ property public final String? secondaryActivityIntentAction;
+ property public final android.content.ComponentName secondaryActivityName;
+ }
+
+ public final class SplitPairRule extends androidx.window.embedding.SplitRule {
+ method public boolean getClearTop();
+ method public java.util.Set<androidx.window.embedding.SplitPairFilter> getFilters();
+ method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithSecondary();
+ method public androidx.window.embedding.SplitRule.FinishBehavior getFinishSecondaryWithPrimary();
+ property public final boolean clearTop;
+ property public final java.util.Set<androidx.window.embedding.SplitPairFilter> filters;
+ property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary;
+ property public final androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary;
+ }
+
+ public static final class SplitPairRule.Builder {
+ ctor public SplitPairRule.Builder(java.util.Set<androidx.window.embedding.SplitPairFilter> filters);
+ method public androidx.window.embedding.SplitPairRule build();
+ method public androidx.window.embedding.SplitPairRule.Builder setClearTop(boolean clearTop);
+ method public androidx.window.embedding.SplitPairRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+ method public androidx.window.embedding.SplitPairRule.Builder setFinishPrimaryWithSecondary(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithSecondary);
+ method public androidx.window.embedding.SplitPairRule.Builder setFinishSecondaryWithPrimary(androidx.window.embedding.SplitRule.FinishBehavior finishSecondaryWithPrimary);
+ method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPairRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPairRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+ method public androidx.window.embedding.SplitPairRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+ method public androidx.window.embedding.SplitPairRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+ method public androidx.window.embedding.SplitPairRule.Builder setTag(String? tag);
+ }
+
+ public final class SplitPlaceholderRule extends androidx.window.embedding.SplitRule {
+ method public java.util.Set<androidx.window.embedding.ActivityFilter> getFilters();
+ method public androidx.window.embedding.SplitRule.FinishBehavior getFinishPrimaryWithPlaceholder();
+ method public android.content.Intent getPlaceholderIntent();
+ method public boolean isSticky();
+ property public final java.util.Set<androidx.window.embedding.ActivityFilter> filters;
+ property public final androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder;
+ property public final boolean isSticky;
+ property public final android.content.Intent placeholderIntent;
+ }
+
+ public static final class SplitPlaceholderRule.Builder {
+ ctor public SplitPlaceholderRule.Builder(java.util.Set<androidx.window.embedding.ActivityFilter> filters, android.content.Intent placeholderIntent);
+ method public androidx.window.embedding.SplitPlaceholderRule build();
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setDefaultSplitAttributes(androidx.window.embedding.SplitAttributes defaultSplitAttributes);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setFinishPrimaryWithPlaceholder(androidx.window.embedding.SplitRule.FinishBehavior finishPrimaryWithPlaceholder);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInLandscape(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMaxAspectRatioInPortrait(androidx.window.embedding.EmbeddingAspectRatio aspectRatio);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinHeightDp(@IntRange(from=0L) int minHeightDp);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinSmallestWidthDp(@IntRange(from=0L) int minSmallestWidthDp);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setMinWidthDp(@IntRange(from=0L) int minWidthDp);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setSticky(boolean isSticky);
+ method public androidx.window.embedding.SplitPlaceholderRule.Builder setTag(String? tag);
+ }
+
+ public class SplitRule extends androidx.window.embedding.EmbeddingRule {
+ method public final androidx.window.embedding.SplitAttributes getDefaultSplitAttributes();
+ method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInLandscape();
+ method public final androidx.window.embedding.EmbeddingAspectRatio getMaxAspectRatioInPortrait();
+ method public final int getMinHeightDp();
+ method public final int getMinSmallestWidthDp();
+ method public final int getMinWidthDp();
+ property public final androidx.window.embedding.SplitAttributes defaultSplitAttributes;
+ property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInLandscape;
+ property public final androidx.window.embedding.EmbeddingAspectRatio maxAspectRatioInPortrait;
+ property public final int minHeightDp;
+ property public final int minSmallestWidthDp;
+ property public final int minWidthDp;
+ field public static final androidx.window.embedding.SplitRule.Companion Companion;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_LANDSCAPE_DEFAULT;
+ field public static final androidx.window.embedding.EmbeddingAspectRatio SPLIT_MAX_ASPECT_RATIO_PORTRAIT_DEFAULT;
+ field public static final int SPLIT_MIN_DIMENSION_ALWAYS_ALLOW = 0; // 0x0
+ field public static final int SPLIT_MIN_DIMENSION_DP_DEFAULT = 600; // 0x258
+ }
+
+ public static final class SplitRule.Companion {
+ }
+
+ public static final class SplitRule.FinishBehavior {
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior ADJACENT;
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior ALWAYS;
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior.Companion Companion;
+ field public static final androidx.window.embedding.SplitRule.FinishBehavior NEVER;
+ }
+
+ public static final class SplitRule.FinishBehavior.Companion {
+ }
+
+}
+
+package androidx.window.layout {
+
+ public interface DisplayFeature {
+ method public android.graphics.Rect getBounds();
+ property public abstract android.graphics.Rect bounds;
+ }
+
+ public interface FoldingFeature extends androidx.window.layout.DisplayFeature {
+ method public androidx.window.layout.FoldingFeature.OcclusionType getOcclusionType();
+ method public androidx.window.layout.FoldingFeature.Orientation getOrientation();
+ method public androidx.window.layout.FoldingFeature.State getState();
+ method public boolean isSeparating();
+ property public abstract boolean isSeparating;
+ property public abstract androidx.window.layout.FoldingFeature.OcclusionType occlusionType;
+ property public abstract androidx.window.layout.FoldingFeature.Orientation orientation;
+ property public abstract androidx.window.layout.FoldingFeature.State state;
+ }
+
+ public static final class FoldingFeature.OcclusionType {
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType FULL;
+ field public static final androidx.window.layout.FoldingFeature.OcclusionType NONE;
+ }
+
+ public static final class FoldingFeature.OcclusionType.Companion {
+ }
+
+ public static final class FoldingFeature.Orientation {
+ field public static final androidx.window.layout.FoldingFeature.Orientation.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.Orientation HORIZONTAL;
+ field public static final androidx.window.layout.FoldingFeature.Orientation VERTICAL;
+ }
+
+ public static final class FoldingFeature.Orientation.Companion {
+ }
+
+ public static final class FoldingFeature.State {
+ field public static final androidx.window.layout.FoldingFeature.State.Companion Companion;
+ field public static final androidx.window.layout.FoldingFeature.State FLAT;
+ field public static final androidx.window.layout.FoldingFeature.State HALF_OPENED;
+ }
+
+ public static final class FoldingFeature.State.Companion {
+ }
+
+ public interface WindowInfoTracker {
+ method public static androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+ method public kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(android.app.Activity activity);
+ method public default kotlinx.coroutines.flow.Flow<androidx.window.layout.WindowLayoutInfo> windowLayoutInfo(@UiContext android.content.Context context);
+ field public static final androidx.window.layout.WindowInfoTracker.Companion Companion;
+ }
+
+ public static final class WindowInfoTracker.Companion {
+ method public androidx.window.layout.WindowInfoTracker getOrCreate(android.content.Context context);
+ }
+
+ public final class WindowLayoutInfo {
+ method public java.util.List<androidx.window.layout.DisplayFeature> getDisplayFeatures();
+ property public final java.util.List<androidx.window.layout.DisplayFeature> displayFeatures;
+ }
+
+ public final class WindowMetrics {
+ method public android.graphics.Rect getBounds();
+ method @SuppressCompatibility @RequiresApi(android.os.Build.VERSION_CODES.R) @androidx.window.core.ExperimentalWindowApi public androidx.core.view.WindowInsetsCompat getWindowInsets();
+ property public final android.graphics.Rect bounds;
+ }
+
+ public interface WindowMetricsCalculator {
+ method public androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(android.app.Activity activity);
+ method public default androidx.window.layout.WindowMetrics computeCurrentWindowMetrics(@UiContext android.content.Context context);
+ method public androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(android.app.Activity activity);
+ method public default androidx.window.layout.WindowMetrics computeMaximumWindowMetrics(@UiContext android.content.Context context);
+ method public static androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ field public static final androidx.window.layout.WindowMetricsCalculator.Companion Companion;
+ }
+
+ public static final class WindowMetricsCalculator.Companion {
+ method public androidx.window.layout.WindowMetricsCalculator getOrCreate();
+ }
+
+}
+
diff --git a/work/work-datatransfer/src/androidTest/java/androidx/work/datatransfer/UserInitiatedTaskRequestTest.kt b/work/work-datatransfer/src/androidTest/java/androidx/work/datatransfer/UserInitiatedTaskRequestTest.kt
index 8b2f117..bc758ac 100644
--- a/work/work-datatransfer/src/androidTest/java/androidx/work/datatransfer/UserInitiatedTaskRequestTest.kt
+++ b/work/work-datatransfer/src/androidTest/java/androidx/work/datatransfer/UserInitiatedTaskRequestTest.kt
@@ -16,8 +16,10 @@
package androidx.work.datatransfer
+import android.content.Intent
import android.net.NetworkCapabilities
import android.net.NetworkRequest
+import android.os.IBinder
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -34,7 +36,7 @@
@Test
fun testDefaultNetworkConstraints() {
- val request = UserInitiatedTaskRequest(MyTask::class.java)
+ val request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java)
val networkRequest = NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
@@ -48,8 +50,8 @@
@Test
fun testCustomNetworkConstraints() {
- val request = UserInitiatedTaskRequest(MyTask::class.java,
- Constraints(NetworkRequest.Builder()
+ val request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java,
+ _constraints = Constraints(NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
.build()
)
@@ -68,15 +70,16 @@
@Test
fun testTags() {
val taskClassName = "androidx.work.datatransfer.UserInitiatedTaskRequestTest\$MyTask"
- var request = UserInitiatedTaskRequest(MyTask::class.java)
+ var request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java)
assertEquals(1, request.tags.size)
assertEquals(taskClassName, request.tags.get(0))
- request = UserInitiatedTaskRequest(MyTask::class.java, _tags = mutableListOf("test"))
+ request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java,
+ _tags = mutableListOf("test"))
assertEquals(2, request.tags.size)
assertTrue(request.tags.contains("test"))
- request = UserInitiatedTaskRequest(MyTask::class.java,
+ request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java,
_tags = mutableListOf("test", "test2"))
assertEquals(3, request.tags.size)
assertTrue(request.tags.contains(taskClassName))
@@ -86,24 +89,24 @@
@Test
fun testDefaultTransferInfo() {
- val request = UserInitiatedTaskRequest(MyTask::class.java)
+ val request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java)
assertNull(request.transferInfo)
}
@Test
fun testCustomTransferInfo() {
- var request = UserInitiatedTaskRequest(MyTask::class.java,
+ var request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java,
_transferInfo = TransferInfo(estimatedDownloadBytes = 1000L))
val transferInfo = TransferInfo(0L, 1000L)
assertEquals(request.transferInfo, transferInfo)
- request = UserInitiatedTaskRequest(MyTask::class.java,
+ request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java,
_transferInfo = TransferInfo(estimatedUploadBytes = 1000L))
val transferInfo2 = TransferInfo(1000L, 0L)
assertEquals(request.transferInfo, transferInfo2)
assertNotEquals(request.transferInfo, transferInfo)
- request = UserInitiatedTaskRequest(MyTask::class.java,
+ request = UserInitiatedTaskRequest(MyTask::class.java, MyFgs::class.java,
_transferInfo = TransferInfo(2000L, 20L))
val transferInfo3 = TransferInfo(2000L, 20L)
assertEquals(request.transferInfo, transferInfo3)
@@ -116,5 +119,25 @@
override suspend fun performTask() {
// test stub
}
+
+ override suspend fun createForegroundInfo(): UitForegroundInfo {
+ // test stub
+ TODO()
+ }
+ }
+
+ private class MyFgs : AbstractUitService() {
+ override fun handleOnStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ // test stub
+ return START_STICKY
+ }
+
+ override fun handleOnDestroyCommand() {
+ // test stub
+ }
+
+ override fun onBind(p0: Intent?): IBinder? {
+ return null
+ }
}
}
diff --git a/work/work-datatransfer/src/main/java/androidx/work/datatransfer/AbstractUitService.kt b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/AbstractUitService.kt
new file mode 100644
index 0000000..28db0c8
--- /dev/null
+++ b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/AbstractUitService.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work.datatransfer
+
+import android.app.Notification
+import android.app.Service
+import android.content.Intent
+
+/**
+ * App developers should migrate their existing foreground service implementation to this new
+ * base class instead of [Service].
+ * App developers are not supposed to call [Service.stopForeground] (or even [Service.stopService])
+ * on their own, otherwise this library will crash unexpectedly.
+ */
+abstract class AbstractUitService : Service() {
+
+ /**
+ * This is an equivalent of the [Service.onStartCommand], however, developers should override
+ * this method instead of the [Service.onStartCommand]. Its return value will be honored if
+ * there are no pending/active [UserInitiatedTask]s, otherwise the return value will be ignored.
+ */
+ abstract fun handleOnStartCommand(intent: Intent?, flags: Int, startId: Int): Int
+
+ /**
+ * This is an equivalent of [Service.onDestroy]. Developers should override this method instead.
+ */
+ abstract fun handleOnDestroyCommand()
+
+ /**
+ * Optional method that can be overridden by apps. Apps can implement their own policy for
+ * how multiplexing for task notifications will behave.
+ * The default notification policy is FIFO.
+ */
+ open fun handleTaskNotification(id: Int, notification: Notification) {
+ TODO()
+ }
+
+ final override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ final override fun onDestroy() {
+ // TODO: notify UserInitiatedTaskManager to stop all running tasks
+ super.onDestroy()
+ }
+}
diff --git a/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UitForegroundInfo.kt b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UitForegroundInfo.kt
new file mode 100644
index 0000000..325712e
--- /dev/null
+++ b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UitForegroundInfo.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.work.datatransfer
+
+import android.app.Notification
+import android.content.pm.ServiceInfo
+import androidx.work.ForegroundInfo
+
+/**
+ * A container class holding information related to the notifications for the
+ * [UserInitiatedTaskRequest].
+ */
+class UitForegroundInfo(
+ /**
+ * The notification id of the notification to be associated with the foreground service.
+ */
+ val notificationId: Int,
+ /**
+ * The notification object to be associated with the foreground service.
+ */
+ val notification: Notification,
+ /**
+ * The foreground service type for the foreground service associated with the task request.
+ *
+ * This is not required to be specified on API versions below 29.
+ *
+ * The default type here will be [ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE]. However, on
+ * API versions 34 and above, a different type must be specified otherwise an
+ * [InvalidForegroundServiceTypeException] will be thrown.
+ */
+ @Suppress("DEPRECATION")
+ val fgsType: Int = ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE,
+ /**
+ * Indicates what should be done with the notification after the foreground service is finished.
+ * By default, the notification will be removed
+ * (see [TaskEndNotificationPolicy.NOTIFICATION_REMOVE])
+ */
+ val taskEndNotificationPolicy: TaskEndNotificationPolicy =
+ TaskEndNotificationPolicy.NOTIFICATION_REMOVE
+) {
+ /**
+ * Internal container variable pointing to the [ForegroundInfo] object in workmanager.
+ */
+ private val foregroundInfo: ForegroundInfo =
+ ForegroundInfo(notificationId, notification, fgsType)
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || javaClass != other.javaClass) return false
+ val that = other as UitForegroundInfo
+ return foregroundInfo == that.foregroundInfo &&
+ taskEndNotificationPolicy == that.taskEndNotificationPolicy
+ }
+
+ override fun hashCode(): Int {
+ var result = foregroundInfo.hashCode()
+ result = 31 * result + taskEndNotificationPolicy.hashCode()
+ return result
+ }
+}
+
+enum class TaskEndNotificationPolicy {
+ /**
+ * This indicates that the notification will be removed when the task is finished.
+ * This is the default behavior.
+ */
+ NOTIFICATION_REMOVE,
+ /**
+ * This indicates that the notification will be detached from the foreground service,
+ * but not removed so it can still be modified if needed.
+ */
+ NOTIFICATION_DETACH
+}
diff --git a/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTask.kt b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTask.kt
index 140aa15..32d6c88 100644
--- a/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTask.kt
+++ b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTask.kt
@@ -46,4 +46,18 @@
* - [JobParameters.STOP_REASON_USER]
*/
abstract suspend fun performTask()
+
+ /**
+ * Override this method to provide the notification information associated with your work.
+ *
+ * <p>On Android 14+, the notification will be delegated to the dedicated JobService.
+ * While on Android 13-, the default policy to this API is FIFO:
+ * whoever calls this API later will get posted as a foreground service notification here.
+ * The notifications from the previous calls to this method would be posted as regular
+ * notifications (unless they have the same notification ID).
+ *
+ * <p> To change this behavior on Android 13-, override
+ * [AbstractUitService.handleTaskNotification]
+ */
+ abstract suspend fun createForegroundInfo(): UitForegroundInfo
}
diff --git a/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTaskRequest.kt b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTaskRequest.kt
index 7fe650b..62aac55 100644
--- a/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTaskRequest.kt
+++ b/work/work-datatransfer/src/main/java/androidx/work/datatransfer/UserInitiatedTaskRequest.kt
@@ -25,6 +25,21 @@
class UserInitiatedTaskRequest constructor(
private val task: Class<out UserInitiatedTask>,
/**
+ * The foreground service which will be used as a fallback solution on Android 14- devices.
+ *
+ * <p>
+ * Upon scheduling the task request, the library will call [Context.startForegroundService] with
+ * [ACTION_UIT_SCHEDULE] on the given service here.
+ * The app needs to call [android.app.Service.startForeground] within a certain amount of time,
+ * otherwise it will crash with a [android.app.ForegroundServiceDidNotStartInTimeException].
+ */
+ private val service: Class<out AbstractUitService>,
+ /**
+ * [ForegroundServiceOnTaskFinishPolicy] indicating what should occur when the task is finished.
+ */
+ private val onTaskFinishPolicy: ForegroundServiceOnTaskFinishPolicy =
+ ForegroundServiceOnTaskFinishPolicy.FOREGROUND_SERVICE_STOP_FOREGROUND,
+ /**
* [Constraints] required for this task to run.
* The default value assumes a requirement of any internet.
*/
@@ -73,6 +88,25 @@
// TODO: update impl
}
+ companion object {
+ const val ACTION_UIT_SCHEDULE =
+ "androidx.work.datatransfer.UserInitiatedTaskRequest.SCHEDULE"
+ }
+
+ enum class ForegroundServiceOnTaskFinishPolicy {
+ /**
+ * This indicates that the foreground service should be stopped when the job is done.
+ * This is the default behavior.
+ */
+ FOREGROUND_SERVICE_STOP_FOREGROUND,
+
+ /**
+ * This indicates that the foreground service should be left as is when the job is done
+ * and the app will manage its lifecycle.
+ */
+ FOREGROUND_SERVICE_DETACH,
+ }
+
/**
* The internal definition of the task states.
*/